diff options
392 files changed, 27362 insertions, 5992 deletions
diff --git a/Documentation/i2c/busses/i2c-viapro b/Documentation/i2c/busses/i2c-viapro index 9363b8bd6109..16775663b9f5 100644 --- a/Documentation/i2c/busses/i2c-viapro +++ b/Documentation/i2c/busses/i2c-viapro | |||
@@ -7,12 +7,10 @@ Supported adapters: | |||
7 | * VIA Technologies, Inc. VT82C686A/B | 7 | * VIA Technologies, Inc. VT82C686A/B |
8 | Datasheet: Sometimes available at the VIA website | 8 | Datasheet: Sometimes available at the VIA website |
9 | 9 | ||
10 | * VIA Technologies, Inc. VT8231, VT8233, VT8233A, VT8235, VT8237 | 10 | * VIA Technologies, Inc. VT8231, VT8233, VT8233A, VT8235, VT8237R |
11 | Datasheet: available on request from Via | 11 | Datasheet: available on request from VIA |
12 | 12 | ||
13 | Authors: | 13 | Authors: |
14 | Frodo Looijaard <frodol@dds.nl>, | ||
15 | Philip Edelbrock <phil@netroedge.com>, | ||
16 | Kyösti Mälkki <kmalkki@cc.hut.fi>, | 14 | Kyösti Mälkki <kmalkki@cc.hut.fi>, |
17 | Mark D. Studebaker <mdsxyz123@yahoo.com>, | 15 | Mark D. Studebaker <mdsxyz123@yahoo.com>, |
18 | Jean Delvare <khali@linux-fr.org> | 16 | Jean Delvare <khali@linux-fr.org> |
diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index cff7b652588a..d19993cc0604 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients | |||
@@ -412,7 +412,7 @@ For now, you can ignore the `flags' parameter. It is there for future use. | |||
412 | release_region(address,FOO_EXTENT); | 412 | release_region(address,FOO_EXTENT); |
413 | /* SENSORS ONLY END */ | 413 | /* SENSORS ONLY END */ |
414 | ERROR1: | 414 | ERROR1: |
415 | kfree(new_client); | 415 | kfree(data); |
416 | ERROR0: | 416 | ERROR0: |
417 | return err; | 417 | return err; |
418 | } | 418 | } |
@@ -443,7 +443,7 @@ much simpler than the attachment code, fortunately! | |||
443 | release_region(client->addr,LM78_EXTENT); | 443 | release_region(client->addr,LM78_EXTENT); |
444 | /* HYBRID SENSORS CHIP ONLY END */ | 444 | /* HYBRID SENSORS CHIP ONLY END */ |
445 | 445 | ||
446 | kfree(data); | 446 | kfree(i2c_get_clientdata(client)); |
447 | return 0; | 447 | return 0; |
448 | } | 448 | } |
449 | 449 | ||
diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt new file mode 100644 index 000000000000..c45daabd3bfe --- /dev/null +++ b/Documentation/networking/dccp.txt | |||
@@ -0,0 +1,56 @@ | |||
1 | DCCP protocol | ||
2 | ============ | ||
3 | |||
4 | Last updated: 10 November 2005 | ||
5 | |||
6 | Contents | ||
7 | ======== | ||
8 | |||
9 | - Introduction | ||
10 | - Missing features | ||
11 | - Socket options | ||
12 | - Notes | ||
13 | |||
14 | Introduction | ||
15 | ============ | ||
16 | |||
17 | Datagram Congestion Control Protocol (DCCP) is an unreliable, connection | ||
18 | based protocol designed to solve issues present in UDP and TCP particularly | ||
19 | for real time and multimedia traffic. | ||
20 | |||
21 | It has a base protocol and pluggable congestion control IDs (CCIDs). | ||
22 | |||
23 | It is at draft RFC status and the homepage for DCCP as a protocol is at: | ||
24 | http://www.icir.org/kohler/dcp/ | ||
25 | |||
26 | Missing features | ||
27 | ================ | ||
28 | |||
29 | The DCCP implementation does not currently have all the features that are in | ||
30 | the draft RFC. | ||
31 | |||
32 | In particular the following are missing: | ||
33 | - CCID2 support | ||
34 | - feature negotiation | ||
35 | |||
36 | When testing against other implementations it appears that elapsed time | ||
37 | options are not coded compliant to the specification. | ||
38 | |||
39 | Socket options | ||
40 | ============== | ||
41 | |||
42 | DCCP_SOCKOPT_PACKET_SIZE is used for CCID3 to set default packet size for | ||
43 | calculations. | ||
44 | |||
45 | DCCP_SOCKOPT_SERVICE sets the service. This is compulsory as per the | ||
46 | specification. If you don't set it you will get EPROTO. | ||
47 | |||
48 | Notes | ||
49 | ===== | ||
50 | |||
51 | SELinux does not yet have support for DCCP. You will need to turn it off or | ||
52 | else you will get EACCES. | ||
53 | |||
54 | DCCP does not travel through NAT successfully at present. This is because | ||
55 | the checksum covers the psuedo-header as per TCP and UDP. It should be | ||
56 | relatively trivial to add Linux NAT support for DCCP. | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 5541f9970b87..0b03a88e88be 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -707,7 +707,7 @@ DCCP PROTOCOL | |||
707 | P: Arnaldo Carvalho de Melo | 707 | P: Arnaldo Carvalho de Melo |
708 | M: acme@mandriva.com | 708 | M: acme@mandriva.com |
709 | L: dccp@vger.kernel.org | 709 | L: dccp@vger.kernel.org |
710 | W: http://www.wlug.org.nz/DCCP | 710 | W: http://linux-net.osdl.org/index.php/DCCP |
711 | S: Maintained | 711 | S: Maintained |
712 | 712 | ||
713 | DECnet NETWORK LAYER | 713 | DECnet NETWORK LAYER |
@@ -347,7 +347,7 @@ AFLAGS_KERNEL = | |||
347 | # Needed to be compatible with the O= option | 347 | # Needed to be compatible with the O= option |
348 | LINUXINCLUDE := -Iinclude \ | 348 | LINUXINCLUDE := -Iinclude \ |
349 | $(if $(KBUILD_SRC),-Iinclude2 -I$(srctree)/include) \ | 349 | $(if $(KBUILD_SRC),-Iinclude2 -I$(srctree)/include) \ |
350 | -imacros include/linux/autoconf.h | 350 | -include include/linux/autoconf.h |
351 | 351 | ||
352 | CPPFLAGS := -D__KERNEL__ $(LINUXINCLUDE) | 352 | CPPFLAGS := -D__KERNEL__ $(LINUXINCLUDE) |
353 | 353 | ||
@@ -407,7 +407,7 @@ outputmakefile: | |||
407 | # of make so .config is not included in this case either (for *config). | 407 | # of make so .config is not included in this case either (for *config). |
408 | 408 | ||
409 | no-dot-config-targets := clean mrproper distclean \ | 409 | no-dot-config-targets := clean mrproper distclean \ |
410 | cscope TAGS tags help %docs check% | 410 | cscope TAGS tags help %docs check% kernelrelease |
411 | 411 | ||
412 | config-targets := 0 | 412 | config-targets := 0 |
413 | mixed-targets := 0 | 413 | mixed-targets := 0 |
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index ec77721507cb..3df7cbd924a1 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -239,6 +239,8 @@ source "arch/arm/plat-omap/Kconfig" | |||
239 | 239 | ||
240 | source "arch/arm/mach-omap1/Kconfig" | 240 | source "arch/arm/mach-omap1/Kconfig" |
241 | 241 | ||
242 | source "arch/arm/mach-omap2/Kconfig" | ||
243 | |||
242 | source "arch/arm/mach-s3c2410/Kconfig" | 244 | source "arch/arm/mach-s3c2410/Kconfig" |
243 | 245 | ||
244 | source "arch/arm/mach-lh7a40x/Kconfig" | 246 | source "arch/arm/mach-lh7a40x/Kconfig" |
diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 114cda7f1b73..81bd2193fe6d 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile | |||
@@ -93,6 +93,7 @@ textaddr-$(CONFIG_ARCH_FORTUNET) := 0xc0008000 | |||
93 | machine-$(CONFIG_ARCH_IXP4XX) := ixp4xx | 93 | machine-$(CONFIG_ARCH_IXP4XX) := ixp4xx |
94 | machine-$(CONFIG_ARCH_IXP2000) := ixp2000 | 94 | machine-$(CONFIG_ARCH_IXP2000) := ixp2000 |
95 | machine-$(CONFIG_ARCH_OMAP1) := omap1 | 95 | machine-$(CONFIG_ARCH_OMAP1) := omap1 |
96 | machine-$(CONFIG_ARCH_OMAP2) := omap2 | ||
96 | incdir-$(CONFIG_ARCH_OMAP) := omap | 97 | incdir-$(CONFIG_ARCH_OMAP) := omap |
97 | machine-$(CONFIG_ARCH_S3C2410) := s3c2410 | 98 | machine-$(CONFIG_ARCH_S3C2410) := s3c2410 |
98 | machine-$(CONFIG_ARCH_LH7A40X) := lh7a40x | 99 | machine-$(CONFIG_ARCH_LH7A40X) := lh7a40x |
diff --git a/arch/arm/configs/omap_h2_1610_defconfig b/arch/arm/configs/omap_h2_1610_defconfig index 4198677cd394..529f0f72e1e9 100644 --- a/arch/arm/configs/omap_h2_1610_defconfig +++ b/arch/arm/configs/omap_h2_1610_defconfig | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Automatically generated make config: don't edit | 2 | # Automatically generated make config: don't edit |
3 | # Linux kernel version: 2.6.13 | 3 | # Linux kernel version: 2.6.14 |
4 | # Mon Sep 5 18:07:12 2005 | 4 | # Wed Nov 9 18:53:40 2005 |
5 | # | 5 | # |
6 | CONFIG_ARM=y | 6 | CONFIG_ARM=y |
7 | CONFIG_MMU=y | 7 | CONFIG_MMU=y |
@@ -22,6 +22,7 @@ CONFIG_INIT_ENV_ARG_LIMIT=32 | |||
22 | # General setup | 22 | # General setup |
23 | # | 23 | # |
24 | CONFIG_LOCALVERSION="" | 24 | CONFIG_LOCALVERSION="" |
25 | CONFIG_LOCALVERSION_AUTO=y | ||
25 | CONFIG_SWAP=y | 26 | CONFIG_SWAP=y |
26 | CONFIG_SYSVIPC=y | 27 | CONFIG_SYSVIPC=y |
27 | # CONFIG_POSIX_MQUEUE is not set | 28 | # CONFIG_POSIX_MQUEUE is not set |
@@ -31,6 +32,7 @@ CONFIG_SYSCTL=y | |||
31 | # CONFIG_HOTPLUG is not set | 32 | # CONFIG_HOTPLUG is not set |
32 | CONFIG_KOBJECT_UEVENT=y | 33 | CONFIG_KOBJECT_UEVENT=y |
33 | # CONFIG_IKCONFIG is not set | 34 | # CONFIG_IKCONFIG is not set |
35 | CONFIG_INITRAMFS_SOURCE="" | ||
34 | # CONFIG_EMBEDDED is not set | 36 | # CONFIG_EMBEDDED is not set |
35 | CONFIG_KALLSYMS=y | 37 | CONFIG_KALLSYMS=y |
36 | # CONFIG_KALLSYMS_EXTRA_PASS is not set | 38 | # CONFIG_KALLSYMS_EXTRA_PASS is not set |
@@ -60,6 +62,23 @@ CONFIG_OBSOLETE_MODPARM=y | |||
60 | # CONFIG_KMOD is not set | 62 | # CONFIG_KMOD is not set |
61 | 63 | ||
62 | # | 64 | # |
65 | # Block layer | ||
66 | # | ||
67 | |||
68 | # | ||
69 | # IO Schedulers | ||
70 | # | ||
71 | CONFIG_IOSCHED_NOOP=y | ||
72 | CONFIG_IOSCHED_AS=y | ||
73 | CONFIG_IOSCHED_DEADLINE=y | ||
74 | CONFIG_IOSCHED_CFQ=y | ||
75 | CONFIG_DEFAULT_AS=y | ||
76 | # CONFIG_DEFAULT_DEADLINE is not set | ||
77 | # CONFIG_DEFAULT_CFQ is not set | ||
78 | # CONFIG_DEFAULT_NOOP is not set | ||
79 | CONFIG_DEFAULT_IOSCHED="anticipatory" | ||
80 | |||
81 | # | ||
63 | # System Type | 82 | # System Type |
64 | # | 83 | # |
65 | # CONFIG_ARCH_CLPS7500 is not set | 84 | # CONFIG_ARCH_CLPS7500 is not set |
@@ -81,6 +100,7 @@ CONFIG_OBSOLETE_MODPARM=y | |||
81 | # CONFIG_ARCH_LH7A40X is not set | 100 | # CONFIG_ARCH_LH7A40X is not set |
82 | CONFIG_ARCH_OMAP=y | 101 | CONFIG_ARCH_OMAP=y |
83 | # CONFIG_ARCH_VERSATILE is not set | 102 | # CONFIG_ARCH_VERSATILE is not set |
103 | # CONFIG_ARCH_REALVIEW is not set | ||
84 | # CONFIG_ARCH_IMX is not set | 104 | # CONFIG_ARCH_IMX is not set |
85 | # CONFIG_ARCH_H720X is not set | 105 | # CONFIG_ARCH_H720X is not set |
86 | # CONFIG_ARCH_AAEC2000 is not set | 106 | # CONFIG_ARCH_AAEC2000 is not set |
@@ -112,7 +132,7 @@ CONFIG_OMAP_SERIAL_WAKE=y | |||
112 | # OMAP Core Type | 132 | # OMAP Core Type |
113 | # | 133 | # |
114 | # CONFIG_ARCH_OMAP730 is not set | 134 | # CONFIG_ARCH_OMAP730 is not set |
115 | # CONFIG_ARCH_OMAP1510 is not set | 135 | # CONFIG_ARCH_OMAP15XX is not set |
116 | CONFIG_ARCH_OMAP16XX=y | 136 | CONFIG_ARCH_OMAP16XX=y |
117 | 137 | ||
118 | # | 138 | # |
@@ -177,6 +197,8 @@ CONFIG_FLATMEM_MANUAL=y | |||
177 | # CONFIG_SPARSEMEM_MANUAL is not set | 197 | # CONFIG_SPARSEMEM_MANUAL is not set |
178 | CONFIG_FLATMEM=y | 198 | CONFIG_FLATMEM=y |
179 | CONFIG_FLAT_NODE_MEM_MAP=y | 199 | CONFIG_FLAT_NODE_MEM_MAP=y |
200 | # CONFIG_SPARSEMEM_STATIC is not set | ||
201 | CONFIG_SPLIT_PTLOCK_CPUS=4096 | ||
180 | # CONFIG_LEDS is not set | 202 | # CONFIG_LEDS is not set |
181 | CONFIG_ALIGNMENT_TRAP=y | 203 | CONFIG_ALIGNMENT_TRAP=y |
182 | 204 | ||
@@ -258,14 +280,19 @@ CONFIG_IP_PNP_BOOTP=y | |||
258 | # CONFIG_INET_ESP is not set | 280 | # CONFIG_INET_ESP is not set |
259 | # CONFIG_INET_IPCOMP is not set | 281 | # CONFIG_INET_IPCOMP is not set |
260 | # CONFIG_INET_TUNNEL is not set | 282 | # CONFIG_INET_TUNNEL is not set |
261 | CONFIG_IP_TCPDIAG=y | 283 | CONFIG_INET_DIAG=y |
262 | # CONFIG_IP_TCPDIAG_IPV6 is not set | 284 | CONFIG_INET_TCP_DIAG=y |
263 | # CONFIG_TCP_CONG_ADVANCED is not set | 285 | # CONFIG_TCP_CONG_ADVANCED is not set |
264 | CONFIG_TCP_CONG_BIC=y | 286 | CONFIG_TCP_CONG_BIC=y |
265 | # CONFIG_IPV6 is not set | 287 | # CONFIG_IPV6 is not set |
266 | # CONFIG_NETFILTER is not set | 288 | # CONFIG_NETFILTER is not set |
267 | 289 | ||
268 | # | 290 | # |
291 | # DCCP Configuration (EXPERIMENTAL) | ||
292 | # | ||
293 | # CONFIG_IP_DCCP is not set | ||
294 | |||
295 | # | ||
269 | # SCTP Configuration (EXPERIMENTAL) | 296 | # SCTP Configuration (EXPERIMENTAL) |
270 | # | 297 | # |
271 | # CONFIG_IP_SCTP is not set | 298 | # CONFIG_IP_SCTP is not set |
@@ -281,6 +308,10 @@ CONFIG_TCP_CONG_BIC=y | |||
281 | # CONFIG_NET_DIVERT is not set | 308 | # CONFIG_NET_DIVERT is not set |
282 | # CONFIG_ECONET is not set | 309 | # CONFIG_ECONET is not set |
283 | # CONFIG_WAN_ROUTER is not set | 310 | # CONFIG_WAN_ROUTER is not set |
311 | |||
312 | # | ||
313 | # QoS and/or fair queueing | ||
314 | # | ||
284 | # CONFIG_NET_SCHED is not set | 315 | # CONFIG_NET_SCHED is not set |
285 | # CONFIG_NET_CLS_ROUTE is not set | 316 | # CONFIG_NET_CLS_ROUTE is not set |
286 | 317 | ||
@@ -291,6 +322,7 @@ CONFIG_TCP_CONG_BIC=y | |||
291 | # CONFIG_HAMRADIO is not set | 322 | # CONFIG_HAMRADIO is not set |
292 | # CONFIG_IRDA is not set | 323 | # CONFIG_IRDA is not set |
293 | # CONFIG_BT is not set | 324 | # CONFIG_BT is not set |
325 | # CONFIG_IEEE80211 is not set | ||
294 | 326 | ||
295 | # | 327 | # |
296 | # Device Drivers | 328 | # Device Drivers |
@@ -328,21 +360,13 @@ CONFIG_BLK_DEV_RAM=y | |||
328 | CONFIG_BLK_DEV_RAM_COUNT=16 | 360 | CONFIG_BLK_DEV_RAM_COUNT=16 |
329 | CONFIG_BLK_DEV_RAM_SIZE=8192 | 361 | CONFIG_BLK_DEV_RAM_SIZE=8192 |
330 | CONFIG_BLK_DEV_INITRD=y | 362 | CONFIG_BLK_DEV_INITRD=y |
331 | CONFIG_INITRAMFS_SOURCE="" | ||
332 | # CONFIG_CDROM_PKTCDVD is not set | 363 | # CONFIG_CDROM_PKTCDVD is not set |
333 | |||
334 | # | ||
335 | # IO Schedulers | ||
336 | # | ||
337 | CONFIG_IOSCHED_NOOP=y | ||
338 | CONFIG_IOSCHED_AS=y | ||
339 | CONFIG_IOSCHED_DEADLINE=y | ||
340 | CONFIG_IOSCHED_CFQ=y | ||
341 | CONFIG_ATA_OVER_ETH=m | 364 | CONFIG_ATA_OVER_ETH=m |
342 | 365 | ||
343 | # | 366 | # |
344 | # SCSI device support | 367 | # SCSI device support |
345 | # | 368 | # |
369 | # CONFIG_RAID_ATTRS is not set | ||
346 | CONFIG_SCSI=y | 370 | CONFIG_SCSI=y |
347 | CONFIG_SCSI_PROC_FS=y | 371 | CONFIG_SCSI_PROC_FS=y |
348 | 372 | ||
@@ -369,10 +393,12 @@ CONFIG_SCSI_PROC_FS=y | |||
369 | # CONFIG_SCSI_SPI_ATTRS is not set | 393 | # CONFIG_SCSI_SPI_ATTRS is not set |
370 | # CONFIG_SCSI_FC_ATTRS is not set | 394 | # CONFIG_SCSI_FC_ATTRS is not set |
371 | # CONFIG_SCSI_ISCSI_ATTRS is not set | 395 | # CONFIG_SCSI_ISCSI_ATTRS is not set |
396 | # CONFIG_SCSI_SAS_ATTRS is not set | ||
372 | 397 | ||
373 | # | 398 | # |
374 | # SCSI low-level drivers | 399 | # SCSI low-level drivers |
375 | # | 400 | # |
401 | # CONFIG_ISCSI_TCP is not set | ||
376 | # CONFIG_SCSI_SATA is not set | 402 | # CONFIG_SCSI_SATA is not set |
377 | # CONFIG_SCSI_DEBUG is not set | 403 | # CONFIG_SCSI_DEBUG is not set |
378 | 404 | ||
@@ -404,6 +430,11 @@ CONFIG_NETDEVICES=y | |||
404 | # CONFIG_TUN is not set | 430 | # CONFIG_TUN is not set |
405 | 431 | ||
406 | # | 432 | # |
433 | # PHY device support | ||
434 | # | ||
435 | # CONFIG_PHYLIB is not set | ||
436 | |||
437 | # | ||
407 | # Ethernet (10 or 100Mbit) | 438 | # Ethernet (10 or 100Mbit) |
408 | # | 439 | # |
409 | CONFIG_NET_ETHERNET=y | 440 | CONFIG_NET_ETHERNET=y |
@@ -439,6 +470,7 @@ CONFIG_PPP=y | |||
439 | # CONFIG_PPP_SYNC_TTY is not set | 470 | # CONFIG_PPP_SYNC_TTY is not set |
440 | # CONFIG_PPP_DEFLATE is not set | 471 | # CONFIG_PPP_DEFLATE is not set |
441 | # CONFIG_PPP_BSDCOMP is not set | 472 | # CONFIG_PPP_BSDCOMP is not set |
473 | # CONFIG_PPP_MPPE is not set | ||
442 | # CONFIG_PPPOE is not set | 474 | # CONFIG_PPPOE is not set |
443 | CONFIG_SLIP=y | 475 | CONFIG_SLIP=y |
444 | CONFIG_SLIP_COMPRESSED=y | 476 | CONFIG_SLIP_COMPRESSED=y |
@@ -541,18 +573,18 @@ CONFIG_WATCHDOG_NOWAYOUT=y | |||
541 | # | 573 | # |
542 | # TPM devices | 574 | # TPM devices |
543 | # | 575 | # |
576 | # CONFIG_TELCLOCK is not set | ||
544 | 577 | ||
545 | # | 578 | # |
546 | # I2C support | 579 | # I2C support |
547 | # | 580 | # |
548 | # CONFIG_I2C is not set | 581 | # CONFIG_I2C is not set |
549 | # CONFIG_I2C_SENSOR is not set | ||
550 | CONFIG_ISP1301_OMAP=y | ||
551 | 582 | ||
552 | # | 583 | # |
553 | # Hardware Monitoring support | 584 | # Hardware Monitoring support |
554 | # | 585 | # |
555 | CONFIG_HWMON=y | 586 | CONFIG_HWMON=y |
587 | # CONFIG_HWMON_VID is not set | ||
556 | # CONFIG_HWMON_DEBUG_CHIP is not set | 588 | # CONFIG_HWMON_DEBUG_CHIP is not set |
557 | 589 | ||
558 | # | 590 | # |
@@ -560,6 +592,10 @@ CONFIG_HWMON=y | |||
560 | # | 592 | # |
561 | 593 | ||
562 | # | 594 | # |
595 | # Multimedia Capabilities Port drivers | ||
596 | # | ||
597 | |||
598 | # | ||
563 | # Multimedia devices | 599 | # Multimedia devices |
564 | # | 600 | # |
565 | # CONFIG_VIDEO_DEV is not set | 601 | # CONFIG_VIDEO_DEV is not set |
@@ -576,7 +612,6 @@ CONFIG_FB=y | |||
576 | # CONFIG_FB_CFB_FILLRECT is not set | 612 | # CONFIG_FB_CFB_FILLRECT is not set |
577 | # CONFIG_FB_CFB_COPYAREA is not set | 613 | # CONFIG_FB_CFB_COPYAREA is not set |
578 | # CONFIG_FB_CFB_IMAGEBLIT is not set | 614 | # CONFIG_FB_CFB_IMAGEBLIT is not set |
579 | # CONFIG_FB_SOFT_CURSOR is not set | ||
580 | # CONFIG_FB_MACMODES is not set | 615 | # CONFIG_FB_MACMODES is not set |
581 | CONFIG_FB_MODE_HELPERS=y | 616 | CONFIG_FB_MODE_HELPERS=y |
582 | # CONFIG_FB_TILEBLITTING is not set | 617 | # CONFIG_FB_TILEBLITTING is not set |
@@ -589,6 +624,7 @@ CONFIG_FB_MODE_HELPERS=y | |||
589 | # CONFIG_VGA_CONSOLE is not set | 624 | # CONFIG_VGA_CONSOLE is not set |
590 | CONFIG_DUMMY_CONSOLE=y | 625 | CONFIG_DUMMY_CONSOLE=y |
591 | CONFIG_FRAMEBUFFER_CONSOLE=y | 626 | CONFIG_FRAMEBUFFER_CONSOLE=y |
627 | # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set | ||
592 | CONFIG_FONTS=y | 628 | CONFIG_FONTS=y |
593 | CONFIG_FONT_8x8=y | 629 | CONFIG_FONT_8x8=y |
594 | CONFIG_FONT_8x16=y | 630 | CONFIG_FONT_8x16=y |
@@ -600,6 +636,7 @@ CONFIG_FONT_8x16=y | |||
600 | # CONFIG_FONT_SUN8x16 is not set | 636 | # CONFIG_FONT_SUN8x16 is not set |
601 | # CONFIG_FONT_SUN12x22 is not set | 637 | # CONFIG_FONT_SUN12x22 is not set |
602 | # CONFIG_FONT_10x18 is not set | 638 | # CONFIG_FONT_10x18 is not set |
639 | # CONFIG_FONT_RL is not set | ||
603 | 640 | ||
604 | # | 641 | # |
605 | # Logo configuration | 642 | # Logo configuration |
@@ -624,10 +661,10 @@ CONFIG_SOUND=y | |||
624 | # Open Sound System | 661 | # Open Sound System |
625 | # | 662 | # |
626 | CONFIG_SOUND_PRIME=y | 663 | CONFIG_SOUND_PRIME=y |
664 | # CONFIG_OBSOLETE_OSS_DRIVER is not set | ||
627 | # CONFIG_SOUND_MSNDCLAS is not set | 665 | # CONFIG_SOUND_MSNDCLAS is not set |
628 | # CONFIG_SOUND_MSNDPIN is not set | 666 | # CONFIG_SOUND_MSNDPIN is not set |
629 | # CONFIG_SOUND_OSS is not set | 667 | # CONFIG_SOUND_OSS is not set |
630 | # CONFIG_SOUND_AD1980 is not set | ||
631 | 668 | ||
632 | # | 669 | # |
633 | # USB support | 670 | # USB support |
@@ -637,22 +674,21 @@ CONFIG_USB_ARCH_HAS_OHCI=y | |||
637 | # CONFIG_USB is not set | 674 | # CONFIG_USB is not set |
638 | 675 | ||
639 | # | 676 | # |
677 | # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' | ||
678 | # | ||
679 | |||
680 | # | ||
640 | # USB Gadget Support | 681 | # USB Gadget Support |
641 | # | 682 | # |
642 | CONFIG_USB_GADGET=y | 683 | # CONFIG_USB_GADGET is not set |
643 | # CONFIG_USB_GADGET_DEBUG_FILES is not set | ||
644 | CONFIG_USB_GADGET_SELECTED=y | ||
645 | # CONFIG_USB_GADGET_NET2280 is not set | 684 | # CONFIG_USB_GADGET_NET2280 is not set |
646 | # CONFIG_USB_GADGET_PXA2XX is not set | 685 | # CONFIG_USB_GADGET_PXA2XX is not set |
647 | # CONFIG_USB_GADGET_GOKU is not set | 686 | # CONFIG_USB_GADGET_GOKU is not set |
648 | # CONFIG_USB_GADGET_LH7A40X is not set | 687 | # CONFIG_USB_GADGET_LH7A40X is not set |
649 | CONFIG_USB_GADGET_OMAP=y | 688 | # CONFIG_USB_GADGET_OMAP is not set |
650 | CONFIG_USB_OMAP=y | ||
651 | # CONFIG_USB_GADGET_DUMMY_HCD is not set | 689 | # CONFIG_USB_GADGET_DUMMY_HCD is not set |
652 | # CONFIG_USB_GADGET_DUALSPEED is not set | ||
653 | # CONFIG_USB_ZERO is not set | 690 | # CONFIG_USB_ZERO is not set |
654 | CONFIG_USB_ETH=y | 691 | # CONFIG_USB_ETH is not set |
655 | CONFIG_USB_ETH_RNDIS=y | ||
656 | # CONFIG_USB_GADGETFS is not set | 692 | # CONFIG_USB_GADGETFS is not set |
657 | # CONFIG_USB_FILE_STORAGE is not set | 693 | # CONFIG_USB_FILE_STORAGE is not set |
658 | # CONFIG_USB_G_SERIAL is not set | 694 | # CONFIG_USB_G_SERIAL is not set |
@@ -673,10 +709,6 @@ CONFIG_EXT2_FS=y | |||
673 | # CONFIG_REISERFS_FS is not set | 709 | # CONFIG_REISERFS_FS is not set |
674 | # CONFIG_JFS_FS is not set | 710 | # CONFIG_JFS_FS is not set |
675 | # CONFIG_FS_POSIX_ACL is not set | 711 | # CONFIG_FS_POSIX_ACL is not set |
676 | |||
677 | # | ||
678 | # XFS support | ||
679 | # | ||
680 | # CONFIG_XFS_FS is not set | 712 | # CONFIG_XFS_FS is not set |
681 | # CONFIG_MINIX_FS is not set | 713 | # CONFIG_MINIX_FS is not set |
682 | CONFIG_ROMFS_FS=y | 714 | CONFIG_ROMFS_FS=y |
@@ -685,6 +717,7 @@ CONFIG_INOTIFY=y | |||
685 | CONFIG_DNOTIFY=y | 717 | CONFIG_DNOTIFY=y |
686 | # CONFIG_AUTOFS_FS is not set | 718 | # CONFIG_AUTOFS_FS is not set |
687 | # CONFIG_AUTOFS4_FS is not set | 719 | # CONFIG_AUTOFS4_FS is not set |
720 | # CONFIG_FUSE_FS is not set | ||
688 | 721 | ||
689 | # | 722 | # |
690 | # CD-ROM/DVD Filesystems | 723 | # CD-ROM/DVD Filesystems |
@@ -706,10 +739,10 @@ CONFIG_FAT_DEFAULT_CODEPAGE=437 | |||
706 | # | 739 | # |
707 | CONFIG_PROC_FS=y | 740 | CONFIG_PROC_FS=y |
708 | CONFIG_SYSFS=y | 741 | CONFIG_SYSFS=y |
709 | # CONFIG_DEVPTS_FS_XATTR is not set | ||
710 | # CONFIG_TMPFS is not set | 742 | # CONFIG_TMPFS is not set |
711 | # CONFIG_HUGETLB_PAGE is not set | 743 | # CONFIG_HUGETLB_PAGE is not set |
712 | CONFIG_RAMFS=y | 744 | CONFIG_RAMFS=y |
745 | # CONFIG_RELAYFS_FS is not set | ||
713 | 746 | ||
714 | # | 747 | # |
715 | # Miscellaneous filesystems | 748 | # Miscellaneous filesystems |
@@ -750,6 +783,7 @@ CONFIG_RPCSEC_GSS_KRB5=y | |||
750 | # CONFIG_NCP_FS is not set | 783 | # CONFIG_NCP_FS is not set |
751 | # CONFIG_CODA_FS is not set | 784 | # CONFIG_CODA_FS is not set |
752 | # CONFIG_AFS_FS is not set | 785 | # CONFIG_AFS_FS is not set |
786 | # CONFIG_9P_FS is not set | ||
753 | 787 | ||
754 | # | 788 | # |
755 | # Partition Types | 789 | # Partition Types |
@@ -859,6 +893,7 @@ CONFIG_CRYPTO_DES=y | |||
859 | # Library routines | 893 | # Library routines |
860 | # | 894 | # |
861 | # CONFIG_CRC_CCITT is not set | 895 | # CONFIG_CRC_CCITT is not set |
896 | # CONFIG_CRC16 is not set | ||
862 | CONFIG_CRC32=y | 897 | CONFIG_CRC32=y |
863 | # CONFIG_LIBCRC32C is not set | 898 | # CONFIG_LIBCRC32C is not set |
864 | CONFIG_ZLIB_INFLATE=y | 899 | CONFIG_ZLIB_INFLATE=y |
diff --git a/arch/arm/lib/csumpartial.S b/arch/arm/lib/csumpartial.S index cb5e3708f118..fe797cf320bb 100644 --- a/arch/arm/lib/csumpartial.S +++ b/arch/arm/lib/csumpartial.S | |||
@@ -39,6 +39,7 @@ td3 .req lr | |||
39 | 39 | ||
40 | /* we must have at least one byte. */ | 40 | /* we must have at least one byte. */ |
41 | tst buf, #1 @ odd address? | 41 | tst buf, #1 @ odd address? |
42 | movne sum, sum, ror #8 | ||
42 | ldrneb td0, [buf], #1 | 43 | ldrneb td0, [buf], #1 |
43 | subne len, len, #1 | 44 | subne len, len, #1 |
44 | adcnes sum, sum, td0, put_byte_1 | 45 | adcnes sum, sum, td0, put_byte_1 |
@@ -103,6 +104,9 @@ ENTRY(csum_partial) | |||
103 | cmp len, #8 @ Ensure that we have at least | 104 | cmp len, #8 @ Ensure that we have at least |
104 | blo .less8 @ 8 bytes to copy. | 105 | blo .less8 @ 8 bytes to copy. |
105 | 106 | ||
107 | tst buf, #1 | ||
108 | movne sum, sum, ror #8 | ||
109 | |||
106 | adds sum, sum, #0 @ C = 0 | 110 | adds sum, sum, #0 @ C = 0 |
107 | tst buf, #3 @ Test destination alignment | 111 | tst buf, #3 @ Test destination alignment |
108 | blne .not_aligned @ aligh destination, return here | 112 | blne .not_aligned @ aligh destination, return here |
diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig index 89762a26495c..385285851cb5 100644 --- a/arch/arm/mach-ixp4xx/Kconfig +++ b/arch/arm/mach-ixp4xx/Kconfig | |||
@@ -8,6 +8,16 @@ menu "Intel IXP4xx Implementation Options" | |||
8 | 8 | ||
9 | comment "IXP4xx Platforms" | 9 | comment "IXP4xx Platforms" |
10 | 10 | ||
11 | # This entry is placed on top because otherwise it would have | ||
12 | # been shown as a submenu. | ||
13 | config MACH_NSLU2 | ||
14 | bool | ||
15 | prompt "NSLU2" if !(MACH_IXDP465 || MACH_IXDPG425 || ARCH_IXDP425 || ARCH_ADI_COYOTE || ARCH_AVILA || ARCH_IXCDP1100 || ARCH_PRPMC1100 || MACH_GTWX5715) | ||
16 | help | ||
17 | Say 'Y' here if you want your kernel to support Linksys's | ||
18 | NSLU2 NAS device. For more information on this platform, | ||
19 | see http://www.nslu2-linux.org | ||
20 | |||
11 | config ARCH_AVILA | 21 | config ARCH_AVILA |
12 | bool "Avila" | 22 | bool "Avila" |
13 | help | 23 | help |
diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile index ddecbda4a633..7a15629c18d0 100644 --- a/arch/arm/mach-ixp4xx/Makefile +++ b/arch/arm/mach-ixp4xx/Makefile | |||
@@ -8,4 +8,5 @@ obj-$(CONFIG_ARCH_IXDP4XX) += ixdp425-pci.o ixdp425-setup.o | |||
8 | obj-$(CONFIG_MACH_IXDPG425) += ixdpg425-pci.o coyote-setup.o | 8 | obj-$(CONFIG_MACH_IXDPG425) += ixdpg425-pci.o coyote-setup.o |
9 | obj-$(CONFIG_ARCH_ADI_COYOTE) += coyote-pci.o coyote-setup.o | 9 | obj-$(CONFIG_ARCH_ADI_COYOTE) += coyote-pci.o coyote-setup.o |
10 | obj-$(CONFIG_MACH_GTWX5715) += gtwx5715-pci.o gtwx5715-setup.o | 10 | obj-$(CONFIG_MACH_GTWX5715) += gtwx5715-pci.o gtwx5715-setup.o |
11 | obj-$(CONFIG_MACH_NSLU2) += nslu2-pci.o nslu2-setup.o nslu2-power.o | ||
11 | 12 | ||
diff --git a/arch/arm/mach-ixp4xx/nslu2-pci.c b/arch/arm/mach-ixp4xx/nslu2-pci.c new file mode 100644 index 000000000000..a575f2e0b2c8 --- /dev/null +++ b/arch/arm/mach-ixp4xx/nslu2-pci.c | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-ixp4xx/nslu2-pci.c | ||
3 | * | ||
4 | * NSLU2 board-level PCI initialization | ||
5 | * | ||
6 | * based on ixdp425-pci.c: | ||
7 | * Copyright (C) 2002 Intel Corporation. | ||
8 | * Copyright (C) 2003-2004 MontaVista Software, Inc. | ||
9 | * | ||
10 | * Maintainer: http://www.nslu2-linux.org/ | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/config.h> | ||
19 | #include <linux/pci.h> | ||
20 | #include <linux/init.h> | ||
21 | |||
22 | #include <asm/mach/pci.h> | ||
23 | #include <asm/mach-types.h> | ||
24 | |||
25 | void __init nslu2_pci_preinit(void) | ||
26 | { | ||
27 | set_irq_type(IRQ_NSLU2_PCI_INTA, IRQT_LOW); | ||
28 | set_irq_type(IRQ_NSLU2_PCI_INTB, IRQT_LOW); | ||
29 | set_irq_type(IRQ_NSLU2_PCI_INTC, IRQT_LOW); | ||
30 | |||
31 | gpio_line_isr_clear(NSLU2_PCI_INTA_PIN); | ||
32 | gpio_line_isr_clear(NSLU2_PCI_INTB_PIN); | ||
33 | gpio_line_isr_clear(NSLU2_PCI_INTC_PIN); | ||
34 | |||
35 | /* INTD is not configured as GPIO is used | ||
36 | * for the power input button. | ||
37 | */ | ||
38 | |||
39 | ixp4xx_pci_preinit(); | ||
40 | } | ||
41 | |||
42 | static int __init nslu2_map_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
43 | { | ||
44 | static int pci_irq_table[NSLU2_PCI_IRQ_LINES] = { | ||
45 | IRQ_NSLU2_PCI_INTA, | ||
46 | IRQ_NSLU2_PCI_INTB, | ||
47 | IRQ_NSLU2_PCI_INTC, | ||
48 | }; | ||
49 | |||
50 | int irq = -1; | ||
51 | |||
52 | if (slot >= 1 && slot <= NSLU2_PCI_MAX_DEV && | ||
53 | pin >= 1 && pin <= NSLU2_PCI_IRQ_LINES) { | ||
54 | irq = pci_irq_table[(slot + pin - 2) % NSLU2_PCI_IRQ_LINES]; | ||
55 | } | ||
56 | |||
57 | return irq; | ||
58 | } | ||
59 | |||
60 | struct hw_pci __initdata nslu2_pci = { | ||
61 | .nr_controllers = 1, | ||
62 | .preinit = nslu2_pci_preinit, | ||
63 | .swizzle = pci_std_swizzle, | ||
64 | .setup = ixp4xx_setup, | ||
65 | .scan = ixp4xx_scan_bus, | ||
66 | .map_irq = nslu2_map_irq, | ||
67 | }; | ||
68 | |||
69 | int __init nslu2_pci_init(void) /* monkey see, monkey do */ | ||
70 | { | ||
71 | if (machine_is_nslu2()) | ||
72 | pci_common_init(&nslu2_pci); | ||
73 | |||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | subsys_initcall(nslu2_pci_init); | ||
diff --git a/arch/arm/mach-ixp4xx/nslu2-power.c b/arch/arm/mach-ixp4xx/nslu2-power.c new file mode 100644 index 000000000000..18fbc8c0fb30 --- /dev/null +++ b/arch/arm/mach-ixp4xx/nslu2-power.c | |||
@@ -0,0 +1,92 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-ixp4xx/nslu2-power.c | ||
3 | * | ||
4 | * NSLU2 Power/Reset driver | ||
5 | * | ||
6 | * Copyright (C) 2005 Tower Technologies | ||
7 | * | ||
8 | * based on nslu2-io.c | ||
9 | * Copyright (C) 2004 Karen Spearel | ||
10 | * | ||
11 | * Author: Alessandro Zummo <a.zummo@towertech.it> | ||
12 | * Maintainers: http://www.nslu2-linux.org/ | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License version 2 as | ||
16 | * published by the Free Software Foundation. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/reboot.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | |||
24 | #include <asm/mach-types.h> | ||
25 | |||
26 | extern void ctrl_alt_del(void); | ||
27 | |||
28 | static irqreturn_t nslu2_power_handler(int irq, void *dev_id, struct pt_regs *regs) | ||
29 | { | ||
30 | /* Signal init to do the ctrlaltdel action, this will bypass init if | ||
31 | * it hasn't started and do a kernel_restart. | ||
32 | */ | ||
33 | ctrl_alt_del(); | ||
34 | |||
35 | return IRQ_HANDLED; | ||
36 | } | ||
37 | |||
38 | static irqreturn_t nslu2_reset_handler(int irq, void *dev_id, struct pt_regs *regs) | ||
39 | { | ||
40 | /* This is the paper-clip reset, it shuts the machine down directly. | ||
41 | */ | ||
42 | machine_power_off(); | ||
43 | |||
44 | return IRQ_HANDLED; | ||
45 | } | ||
46 | |||
47 | static int __init nslu2_power_init(void) | ||
48 | { | ||
49 | if (!(machine_is_nslu2())) | ||
50 | return 0; | ||
51 | |||
52 | *IXP4XX_GPIO_GPISR = 0x20400000; /* read the 2 irqs to clr */ | ||
53 | |||
54 | set_irq_type(NSLU2_RB_IRQ, IRQT_LOW); | ||
55 | set_irq_type(NSLU2_PB_IRQ, IRQT_HIGH); | ||
56 | |||
57 | gpio_line_isr_clear(NSLU2_RB_GPIO); | ||
58 | gpio_line_isr_clear(NSLU2_PB_GPIO); | ||
59 | |||
60 | if (request_irq(NSLU2_RB_IRQ, &nslu2_reset_handler, | ||
61 | SA_INTERRUPT, "NSLU2 reset button", NULL) < 0) { | ||
62 | |||
63 | printk(KERN_DEBUG "Reset Button IRQ %d not available\n", | ||
64 | NSLU2_RB_IRQ); | ||
65 | |||
66 | return -EIO; | ||
67 | } | ||
68 | |||
69 | if (request_irq(NSLU2_PB_IRQ, &nslu2_power_handler, | ||
70 | SA_INTERRUPT, "NSLU2 power button", NULL) < 0) { | ||
71 | |||
72 | printk(KERN_DEBUG "Power Button IRQ %d not available\n", | ||
73 | NSLU2_PB_IRQ); | ||
74 | |||
75 | return -EIO; | ||
76 | } | ||
77 | |||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | static void __exit nslu2_power_exit(void) | ||
82 | { | ||
83 | free_irq(NSLU2_RB_IRQ, NULL); | ||
84 | free_irq(NSLU2_PB_IRQ, NULL); | ||
85 | } | ||
86 | |||
87 | module_init(nslu2_power_init); | ||
88 | module_exit(nslu2_power_exit); | ||
89 | |||
90 | MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); | ||
91 | MODULE_DESCRIPTION("NSLU2 Power/Reset driver"); | ||
92 | MODULE_LICENSE("GPL"); | ||
diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c new file mode 100644 index 000000000000..289e94cb65c2 --- /dev/null +++ b/arch/arm/mach-ixp4xx/nslu2-setup.c | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-ixp4xx/nslu2-setup.c | ||
3 | * | ||
4 | * NSLU2 board-setup | ||
5 | * | ||
6 | * based ixdp425-setup.c: | ||
7 | * Copyright (C) 2003-2004 MontaVista Software, Inc. | ||
8 | * | ||
9 | * Author: Mark Rakes <mrakes at mac.com> | ||
10 | * Maintainers: http://www.nslu2-linux.org/ | ||
11 | * | ||
12 | * Fixed missing init_time in MACHINE_START kas11 10/22/04 | ||
13 | * Changed to conform to new style __init ixdp425 kas11 10/22/04 | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/serial.h> | ||
18 | #include <linux/serial_8250.h> | ||
19 | |||
20 | #include <asm/mach-types.h> | ||
21 | #include <asm/mach/arch.h> | ||
22 | #include <asm/mach/flash.h> | ||
23 | |||
24 | static struct flash_platform_data nslu2_flash_data = { | ||
25 | .map_name = "cfi_probe", | ||
26 | .width = 2, | ||
27 | }; | ||
28 | |||
29 | static struct resource nslu2_flash_resource = { | ||
30 | .start = NSLU2_FLASH_BASE, | ||
31 | .end = NSLU2_FLASH_BASE + NSLU2_FLASH_SIZE, | ||
32 | .flags = IORESOURCE_MEM, | ||
33 | }; | ||
34 | |||
35 | static struct platform_device nslu2_flash = { | ||
36 | .name = "IXP4XX-Flash", | ||
37 | .id = 0, | ||
38 | .dev.platform_data = &nslu2_flash_data, | ||
39 | .num_resources = 1, | ||
40 | .resource = &nslu2_flash_resource, | ||
41 | }; | ||
42 | |||
43 | static struct ixp4xx_i2c_pins nslu2_i2c_gpio_pins = { | ||
44 | .sda_pin = NSLU2_SDA_PIN, | ||
45 | .scl_pin = NSLU2_SCL_PIN, | ||
46 | }; | ||
47 | |||
48 | static struct platform_device nslu2_i2c_controller = { | ||
49 | .name = "IXP4XX-I2C", | ||
50 | .id = 0, | ||
51 | .dev.platform_data = &nslu2_i2c_gpio_pins, | ||
52 | .num_resources = 0, | ||
53 | }; | ||
54 | |||
55 | static struct resource nslu2_uart_resources[] = { | ||
56 | { | ||
57 | .start = IXP4XX_UART1_BASE_PHYS, | ||
58 | .end = IXP4XX_UART1_BASE_PHYS + 0x0fff, | ||
59 | .flags = IORESOURCE_MEM, | ||
60 | }, | ||
61 | { | ||
62 | .start = IXP4XX_UART2_BASE_PHYS, | ||
63 | .end = IXP4XX_UART2_BASE_PHYS + 0x0fff, | ||
64 | .flags = IORESOURCE_MEM, | ||
65 | } | ||
66 | }; | ||
67 | |||
68 | static struct plat_serial8250_port nslu2_uart_data[] = { | ||
69 | { | ||
70 | .mapbase = IXP4XX_UART1_BASE_PHYS, | ||
71 | .membase = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET, | ||
72 | .irq = IRQ_IXP4XX_UART1, | ||
73 | .flags = UPF_BOOT_AUTOCONF, | ||
74 | .iotype = UPIO_MEM, | ||
75 | .regshift = 2, | ||
76 | .uartclk = IXP4XX_UART_XTAL, | ||
77 | }, | ||
78 | { | ||
79 | .mapbase = IXP4XX_UART2_BASE_PHYS, | ||
80 | .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET, | ||
81 | .irq = IRQ_IXP4XX_UART2, | ||
82 | .flags = UPF_BOOT_AUTOCONF, | ||
83 | .iotype = UPIO_MEM, | ||
84 | .regshift = 2, | ||
85 | .uartclk = IXP4XX_UART_XTAL, | ||
86 | }, | ||
87 | { } | ||
88 | }; | ||
89 | |||
90 | static struct platform_device nslu2_uart = { | ||
91 | .name = "serial8250", | ||
92 | .id = PLAT8250_DEV_PLATFORM, | ||
93 | .dev.platform_data = nslu2_uart_data, | ||
94 | .num_resources = 2, | ||
95 | .resource = nslu2_uart_resources, | ||
96 | }; | ||
97 | |||
98 | static struct platform_device *nslu2_devices[] __initdata = { | ||
99 | &nslu2_i2c_controller, | ||
100 | &nslu2_flash, | ||
101 | &nslu2_uart, | ||
102 | }; | ||
103 | |||
104 | static void nslu2_power_off(void) | ||
105 | { | ||
106 | /* This causes the box to drop the power and go dead. */ | ||
107 | |||
108 | /* enable the pwr cntl gpio */ | ||
109 | gpio_line_config(NSLU2_PO_GPIO, IXP4XX_GPIO_OUT); | ||
110 | |||
111 | /* do the deed */ | ||
112 | gpio_line_set(NSLU2_PO_GPIO, IXP4XX_GPIO_HIGH); | ||
113 | } | ||
114 | |||
115 | static void __init nslu2_init(void) | ||
116 | { | ||
117 | ixp4xx_sys_init(); | ||
118 | |||
119 | pm_power_off = nslu2_power_off; | ||
120 | |||
121 | platform_add_devices(nslu2_devices, ARRAY_SIZE(nslu2_devices)); | ||
122 | } | ||
123 | |||
124 | MACHINE_START(NSLU2, "Linksys NSLU2") | ||
125 | /* Maintainer: www.nslu2-linux.org */ | ||
126 | .phys_ram = PHYS_OFFSET, | ||
127 | .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, | ||
128 | .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC, | ||
129 | .boot_params = 0x00000100, | ||
130 | .map_io = ixp4xx_map_io, | ||
131 | .init_irq = ixp4xx_init_irq, | ||
132 | .timer = &ixp4xx_timer, | ||
133 | .init_machine = nslu2_init, | ||
134 | MACHINE_END | ||
diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig index 27fc2e8e5fca..86a0f0d14345 100644 --- a/arch/arm/mach-omap1/Kconfig +++ b/arch/arm/mach-omap1/Kconfig | |||
@@ -6,10 +6,10 @@ config ARCH_OMAP730 | |||
6 | bool "OMAP730 Based System" | 6 | bool "OMAP730 Based System" |
7 | select ARCH_OMAP_OTG | 7 | select ARCH_OMAP_OTG |
8 | 8 | ||
9 | config ARCH_OMAP1510 | 9 | config ARCH_OMAP15XX |
10 | depends on ARCH_OMAP1 | 10 | depends on ARCH_OMAP1 |
11 | default y | 11 | default y |
12 | bool "OMAP1510 Based System" | 12 | bool "OMAP15xx Based System" |
13 | 13 | ||
14 | config ARCH_OMAP16XX | 14 | config ARCH_OMAP16XX |
15 | depends on ARCH_OMAP1 | 15 | depends on ARCH_OMAP1 |
@@ -21,7 +21,7 @@ comment "OMAP Board Type" | |||
21 | 21 | ||
22 | config MACH_OMAP_INNOVATOR | 22 | config MACH_OMAP_INNOVATOR |
23 | bool "TI Innovator" | 23 | bool "TI Innovator" |
24 | depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX) | 24 | depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX) |
25 | help | 25 | help |
26 | TI OMAP 1510 or 1610 Innovator board support. Say Y here if you | 26 | TI OMAP 1510 or 1610 Innovator board support. Say Y here if you |
27 | have such a board. | 27 | have such a board. |
@@ -64,20 +64,30 @@ config MACH_OMAP_PERSEUS2 | |||
64 | 64 | ||
65 | config MACH_VOICEBLUE | 65 | config MACH_VOICEBLUE |
66 | bool "Voiceblue" | 66 | bool "Voiceblue" |
67 | depends on ARCH_OMAP1 && ARCH_OMAP1510 | 67 | depends on ARCH_OMAP1 && ARCH_OMAP15XX |
68 | help | 68 | help |
69 | Support for Voiceblue GSM/VoIP gateway. Say Y here if you have | 69 | Support for Voiceblue GSM/VoIP gateway. Say Y here if you have |
70 | such a board. | 70 | such a board. |
71 | 71 | ||
72 | config MACH_NETSTAR | 72 | config MACH_NETSTAR |
73 | bool "NetStar" | 73 | bool "NetStar" |
74 | depends on ARCH_OMAP1 && ARCH_OMAP1510 | 74 | depends on ARCH_OMAP1 && ARCH_OMAP15XX |
75 | help | 75 | help |
76 | Support for NetStar PBX. Say Y here if you have such a board. | 76 | Support for NetStar PBX. Say Y here if you have such a board. |
77 | 77 | ||
78 | config MACH_OMAP_PALMTE | ||
79 | bool "Palm Tungsten E" | ||
80 | depends on ARCH_OMAP1 && ARCH_OMAP15XX | ||
81 | help | ||
82 | Support for the Palm Tungsten E PDA. Currently only the LCD panel | ||
83 | is supported. To boot the kernel, you'll need a PalmOS compatible | ||
84 | bootloader; check out http://palmtelinux.sourceforge.net for more | ||
85 | informations. | ||
86 | Say Y here if you have such a PDA, say NO otherwise. | ||
87 | |||
78 | config MACH_OMAP_GENERIC | 88 | config MACH_OMAP_GENERIC |
79 | bool "Generic OMAP board" | 89 | bool "Generic OMAP board" |
80 | depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX) | 90 | depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX) |
81 | help | 91 | help |
82 | Support for generic OMAP-1510, 1610 or 1710 board with | 92 | Support for generic OMAP-1510, 1610 or 1710 board with |
83 | no FPGA. Can be used as template for porting Linux to | 93 | no FPGA. Can be used as template for porting Linux to |
@@ -121,32 +131,32 @@ config OMAP_ARM_182MHZ | |||
121 | 131 | ||
122 | config OMAP_ARM_168MHZ | 132 | config OMAP_ARM_168MHZ |
123 | bool "OMAP ARM 168 MHz CPU" | 133 | bool "OMAP ARM 168 MHz CPU" |
124 | depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730) | 134 | depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730) |
125 | help | 135 | help |
126 | Enable 168MHz clock for OMAP CPU. If unsure, say N. | 136 | Enable 168MHz clock for OMAP CPU. If unsure, say N. |
127 | 137 | ||
128 | config OMAP_ARM_150MHZ | 138 | config OMAP_ARM_150MHZ |
129 | bool "OMAP ARM 150 MHz CPU" | 139 | bool "OMAP ARM 150 MHz CPU" |
130 | depends on ARCH_OMAP1 && ARCH_OMAP1510 | 140 | depends on ARCH_OMAP1 && ARCH_OMAP15XX |
131 | help | 141 | help |
132 | Enable 150MHz clock for OMAP CPU. If unsure, say N. | 142 | Enable 150MHz clock for OMAP CPU. If unsure, say N. |
133 | 143 | ||
134 | config OMAP_ARM_120MHZ | 144 | config OMAP_ARM_120MHZ |
135 | bool "OMAP ARM 120 MHz CPU" | 145 | bool "OMAP ARM 120 MHz CPU" |
136 | depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730) | 146 | depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730) |
137 | help | 147 | help |
138 | Enable 120MHz clock for OMAP CPU. If unsure, say N. | 148 | Enable 120MHz clock for OMAP CPU. If unsure, say N. |
139 | 149 | ||
140 | config OMAP_ARM_60MHZ | 150 | config OMAP_ARM_60MHZ |
141 | bool "OMAP ARM 60 MHz CPU" | 151 | bool "OMAP ARM 60 MHz CPU" |
142 | depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730) | 152 | depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730) |
143 | default y | 153 | default y |
144 | help | 154 | help |
145 | Enable 60MHz clock for OMAP CPU. If unsure, say Y. | 155 | Enable 60MHz clock for OMAP CPU. If unsure, say Y. |
146 | 156 | ||
147 | config OMAP_ARM_30MHZ | 157 | config OMAP_ARM_30MHZ |
148 | bool "OMAP ARM 30 MHz CPU" | 158 | bool "OMAP ARM 30 MHz CPU" |
149 | depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730) | 159 | depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730) |
150 | help | 160 | help |
151 | Enable 30MHz clock for OMAP CPU. If unsure, say N. | 161 | Enable 30MHz clock for OMAP CPU. If unsure, say N. |
152 | 162 | ||
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile index 181a93deaaee..b0b00156faae 100644 --- a/arch/arm/mach-omap1/Makefile +++ b/arch/arm/mach-omap1/Makefile | |||
@@ -3,7 +3,7 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | # Common support | 5 | # Common support |
6 | obj-y := io.o id.o irq.o time.o serial.o devices.o | 6 | obj-y := io.o id.o clock.o irq.o time.o mux.o serial.o devices.o |
7 | led-y := leds.o | 7 | led-y := leds.o |
8 | 8 | ||
9 | # Specific board support | 9 | # Specific board support |
@@ -15,8 +15,9 @@ obj-$(CONFIG_MACH_OMAP_OSK) += board-osk.o | |||
15 | obj-$(CONFIG_MACH_OMAP_H3) += board-h3.o | 15 | obj-$(CONFIG_MACH_OMAP_H3) += board-h3.o |
16 | obj-$(CONFIG_MACH_VOICEBLUE) += board-voiceblue.o | 16 | obj-$(CONFIG_MACH_VOICEBLUE) += board-voiceblue.o |
17 | obj-$(CONFIG_MACH_NETSTAR) += board-netstar.o | 17 | obj-$(CONFIG_MACH_NETSTAR) += board-netstar.o |
18 | obj-$(CONFIG_MACH_OMAP_PALMTE) += board-palmte.o | ||
18 | 19 | ||
19 | ifeq ($(CONFIG_ARCH_OMAP1510),y) | 20 | ifeq ($(CONFIG_ARCH_OMAP15XX),y) |
20 | # Innovator-1510 FPGA | 21 | # Innovator-1510 FPGA |
21 | obj-$(CONFIG_MACH_OMAP_INNOVATOR) += fpga.o | 22 | obj-$(CONFIG_MACH_OMAP_INNOVATOR) += fpga.o |
22 | endif | 23 | endif |
diff --git a/arch/arm/mach-omap1/board-generic.c b/arch/arm/mach-omap1/board-generic.c index c209c7172a9a..4b292e93fbe2 100644 --- a/arch/arm/mach-omap1/board-generic.c +++ b/arch/arm/mach-omap1/board-generic.c | |||
@@ -15,7 +15,7 @@ | |||
15 | 15 | ||
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/device.h> | 18 | #include <linux/platform_device.h> |
19 | 19 | ||
20 | #include <asm/hardware.h> | 20 | #include <asm/hardware.h> |
21 | #include <asm/mach-types.h> | 21 | #include <asm/mach-types.h> |
@@ -28,8 +28,6 @@ | |||
28 | #include <asm/arch/board.h> | 28 | #include <asm/arch/board.h> |
29 | #include <asm/arch/common.h> | 29 | #include <asm/arch/common.h> |
30 | 30 | ||
31 | static int __initdata generic_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1}; | ||
32 | |||
33 | static void __init omap_generic_init_irq(void) | 31 | static void __init omap_generic_init_irq(void) |
34 | { | 32 | { |
35 | omap_init_irq(); | 33 | omap_init_irq(); |
@@ -37,7 +35,7 @@ static void __init omap_generic_init_irq(void) | |||
37 | 35 | ||
38 | /* assume no Mini-AB port */ | 36 | /* assume no Mini-AB port */ |
39 | 37 | ||
40 | #ifdef CONFIG_ARCH_OMAP1510 | 38 | #ifdef CONFIG_ARCH_OMAP15XX |
41 | static struct omap_usb_config generic1510_usb_config __initdata = { | 39 | static struct omap_usb_config generic1510_usb_config __initdata = { |
42 | .register_host = 1, | 40 | .register_host = 1, |
43 | .register_dev = 1, | 41 | .register_dev = 1, |
@@ -76,21 +74,19 @@ static struct omap_mmc_config generic_mmc_config __initdata = { | |||
76 | 74 | ||
77 | #endif | 75 | #endif |
78 | 76 | ||
77 | static struct omap_uart_config generic_uart_config __initdata = { | ||
78 | .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), | ||
79 | }; | ||
80 | |||
79 | static struct omap_board_config_kernel generic_config[] = { | 81 | static struct omap_board_config_kernel generic_config[] = { |
80 | { OMAP_TAG_USB, NULL }, | 82 | { OMAP_TAG_USB, NULL }, |
81 | { OMAP_TAG_MMC, &generic_mmc_config }, | 83 | { OMAP_TAG_MMC, &generic_mmc_config }, |
84 | { OMAP_TAG_UART, &generic_uart_config }, | ||
82 | }; | 85 | }; |
83 | 86 | ||
84 | static void __init omap_generic_init(void) | 87 | static void __init omap_generic_init(void) |
85 | { | 88 | { |
86 | const struct omap_uart_config *uart_conf; | 89 | #ifdef CONFIG_ARCH_OMAP15XX |
87 | |||
88 | /* | ||
89 | * Make sure the serial ports are muxed on at this point. | ||
90 | * You have to mux them off in device drivers later on | ||
91 | * if not needed. | ||
92 | */ | ||
93 | #ifdef CONFIG_ARCH_OMAP1510 | ||
94 | if (cpu_is_omap1510()) { | 90 | if (cpu_is_omap1510()) { |
95 | generic_config[0].data = &generic1510_usb_config; | 91 | generic_config[0].data = &generic1510_usb_config; |
96 | } | 92 | } |
@@ -101,20 +97,9 @@ static void __init omap_generic_init(void) | |||
101 | } | 97 | } |
102 | #endif | 98 | #endif |
103 | 99 | ||
104 | uart_conf = omap_get_config(OMAP_TAG_UART, struct omap_uart_config); | ||
105 | if (uart_conf != NULL) { | ||
106 | unsigned int enabled_ports, i; | ||
107 | |||
108 | enabled_ports = uart_conf->enabled_uarts; | ||
109 | for (i = 0; i < 3; i++) { | ||
110 | if (!(enabled_ports & (1 << i))) | ||
111 | generic_serial_ports[i] = 0; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | omap_board_config = generic_config; | 100 | omap_board_config = generic_config; |
116 | omap_board_config_size = ARRAY_SIZE(generic_config); | 101 | omap_board_config_size = ARRAY_SIZE(generic_config); |
117 | omap_serial_init(generic_serial_ports); | 102 | omap_serial_init(); |
118 | } | 103 | } |
119 | 104 | ||
120 | static void __init omap_generic_map_io(void) | 105 | static void __init omap_generic_map_io(void) |
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c index 4ee6bd8a50b8..a07e2c9307fa 100644 --- a/arch/arm/mach-omap1/board-h2.c +++ b/arch/arm/mach-omap1/board-h2.c | |||
@@ -40,8 +40,6 @@ | |||
40 | 40 | ||
41 | extern int omap_gpio_init(void); | 41 | extern int omap_gpio_init(void); |
42 | 42 | ||
43 | static int __initdata h2_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1}; | ||
44 | |||
45 | static struct mtd_partition h2_partitions[] = { | 43 | static struct mtd_partition h2_partitions[] = { |
46 | /* bootloader (U-Boot, etc) in first sector */ | 44 | /* bootloader (U-Boot, etc) in first sector */ |
47 | { | 45 | { |
@@ -160,9 +158,20 @@ static struct omap_mmc_config h2_mmc_config __initdata = { | |||
160 | }, | 158 | }, |
161 | }; | 159 | }; |
162 | 160 | ||
161 | static struct omap_uart_config h2_uart_config __initdata = { | ||
162 | .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), | ||
163 | }; | ||
164 | |||
165 | static struct omap_lcd_config h2_lcd_config __initdata = { | ||
166 | .panel_name = "h2", | ||
167 | .ctrl_name = "internal", | ||
168 | }; | ||
169 | |||
163 | static struct omap_board_config_kernel h2_config[] = { | 170 | static struct omap_board_config_kernel h2_config[] = { |
164 | { OMAP_TAG_USB, &h2_usb_config }, | 171 | { OMAP_TAG_USB, &h2_usb_config }, |
165 | { OMAP_TAG_MMC, &h2_mmc_config }, | 172 | { OMAP_TAG_MMC, &h2_mmc_config }, |
173 | { OMAP_TAG_UART, &h2_uart_config }, | ||
174 | { OMAP_TAG_LCD, &h2_lcd_config }, | ||
166 | }; | 175 | }; |
167 | 176 | ||
168 | static void __init h2_init(void) | 177 | static void __init h2_init(void) |
@@ -180,12 +189,12 @@ static void __init h2_init(void) | |||
180 | platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices)); | 189 | platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices)); |
181 | omap_board_config = h2_config; | 190 | omap_board_config = h2_config; |
182 | omap_board_config_size = ARRAY_SIZE(h2_config); | 191 | omap_board_config_size = ARRAY_SIZE(h2_config); |
192 | omap_serial_init(); | ||
183 | } | 193 | } |
184 | 194 | ||
185 | static void __init h2_map_io(void) | 195 | static void __init h2_map_io(void) |
186 | { | 196 | { |
187 | omap_map_common_io(); | 197 | omap_map_common_io(); |
188 | omap_serial_init(h2_serial_ports); | ||
189 | } | 198 | } |
190 | 199 | ||
191 | MACHINE_START(OMAP_H2, "TI-H2") | 200 | MACHINE_START(OMAP_H2, "TI-H2") |
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c index fc824361430d..668e278433c2 100644 --- a/arch/arm/mach-omap1/board-h3.c +++ b/arch/arm/mach-omap1/board-h3.c | |||
@@ -41,8 +41,6 @@ | |||
41 | 41 | ||
42 | extern int omap_gpio_init(void); | 42 | extern int omap_gpio_init(void); |
43 | 43 | ||
44 | static int __initdata h3_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1}; | ||
45 | |||
46 | static struct mtd_partition h3_partitions[] = { | 44 | static struct mtd_partition h3_partitions[] = { |
47 | /* bootloader (U-Boot, etc) in first sector */ | 45 | /* bootloader (U-Boot, etc) in first sector */ |
48 | { | 46 | { |
@@ -168,9 +166,20 @@ static struct omap_mmc_config h3_mmc_config __initdata = { | |||
168 | }, | 166 | }, |
169 | }; | 167 | }; |
170 | 168 | ||
169 | static struct omap_uart_config h3_uart_config __initdata = { | ||
170 | .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), | ||
171 | }; | ||
172 | |||
173 | static struct omap_lcd_config h3_lcd_config __initdata = { | ||
174 | .panel_name = "h3", | ||
175 | .ctrl_name = "internal", | ||
176 | }; | ||
177 | |||
171 | static struct omap_board_config_kernel h3_config[] = { | 178 | static struct omap_board_config_kernel h3_config[] = { |
172 | { OMAP_TAG_USB, &h3_usb_config }, | 179 | { OMAP_TAG_USB, &h3_usb_config }, |
173 | { OMAP_TAG_MMC, &h3_mmc_config }, | 180 | { OMAP_TAG_MMC, &h3_mmc_config }, |
181 | { OMAP_TAG_UART, &h3_uart_config }, | ||
182 | { OMAP_TAG_LCD, &h3_lcd_config }, | ||
174 | }; | 183 | }; |
175 | 184 | ||
176 | static void __init h3_init(void) | 185 | static void __init h3_init(void) |
@@ -180,6 +189,7 @@ static void __init h3_init(void) | |||
180 | (void) platform_add_devices(devices, ARRAY_SIZE(devices)); | 189 | (void) platform_add_devices(devices, ARRAY_SIZE(devices)); |
181 | omap_board_config = h3_config; | 190 | omap_board_config = h3_config; |
182 | omap_board_config_size = ARRAY_SIZE(h3_config); | 191 | omap_board_config_size = ARRAY_SIZE(h3_config); |
192 | omap_serial_init(); | ||
183 | } | 193 | } |
184 | 194 | ||
185 | static void __init h3_init_smc91x(void) | 195 | static void __init h3_init_smc91x(void) |
@@ -201,7 +211,6 @@ void h3_init_irq(void) | |||
201 | static void __init h3_map_io(void) | 211 | static void __init h3_map_io(void) |
202 | { | 212 | { |
203 | omap_map_common_io(); | 213 | omap_map_common_io(); |
204 | omap_serial_init(h3_serial_ports); | ||
205 | } | 214 | } |
206 | 215 | ||
207 | MACHINE_START(OMAP_H3, "TI OMAP1710 H3 board") | 216 | MACHINE_START(OMAP_H3, "TI OMAP1710 H3 board") |
diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c index a2eac853b2da..95f1ff36cdcb 100644 --- a/arch/arm/mach-omap1/board-innovator.c +++ b/arch/arm/mach-omap1/board-innovator.c | |||
@@ -36,8 +36,6 @@ | |||
36 | #include <asm/arch/usb.h> | 36 | #include <asm/arch/usb.h> |
37 | #include <asm/arch/common.h> | 37 | #include <asm/arch/common.h> |
38 | 38 | ||
39 | static int __initdata innovator_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1}; | ||
40 | |||
41 | static struct mtd_partition innovator_partitions[] = { | 39 | static struct mtd_partition innovator_partitions[] = { |
42 | /* bootloader (U-Boot, etc) in first sector */ | 40 | /* bootloader (U-Boot, etc) in first sector */ |
43 | { | 41 | { |
@@ -99,7 +97,7 @@ static struct platform_device innovator_flash_device = { | |||
99 | .resource = &innovator_flash_resource, | 97 | .resource = &innovator_flash_resource, |
100 | }; | 98 | }; |
101 | 99 | ||
102 | #ifdef CONFIG_ARCH_OMAP1510 | 100 | #ifdef CONFIG_ARCH_OMAP15XX |
103 | 101 | ||
104 | /* Only FPGA needs to be mapped here. All others are done with ioremap */ | 102 | /* Only FPGA needs to be mapped here. All others are done with ioremap */ |
105 | static struct map_desc innovator1510_io_desc[] __initdata = { | 103 | static struct map_desc innovator1510_io_desc[] __initdata = { |
@@ -136,7 +134,7 @@ static struct platform_device *innovator1510_devices[] __initdata = { | |||
136 | &innovator1510_smc91x_device, | 134 | &innovator1510_smc91x_device, |
137 | }; | 135 | }; |
138 | 136 | ||
139 | #endif /* CONFIG_ARCH_OMAP1510 */ | 137 | #endif /* CONFIG_ARCH_OMAP15XX */ |
140 | 138 | ||
141 | #ifdef CONFIG_ARCH_OMAP16XX | 139 | #ifdef CONFIG_ARCH_OMAP16XX |
142 | 140 | ||
@@ -185,7 +183,7 @@ void innovator_init_irq(void) | |||
185 | { | 183 | { |
186 | omap_init_irq(); | 184 | omap_init_irq(); |
187 | omap_gpio_init(); | 185 | omap_gpio_init(); |
188 | #ifdef CONFIG_ARCH_OMAP1510 | 186 | #ifdef CONFIG_ARCH_OMAP15XX |
189 | if (cpu_is_omap1510()) { | 187 | if (cpu_is_omap1510()) { |
190 | omap1510_fpga_init_irq(); | 188 | omap1510_fpga_init_irq(); |
191 | } | 189 | } |
@@ -193,7 +191,7 @@ void innovator_init_irq(void) | |||
193 | innovator_init_smc91x(); | 191 | innovator_init_smc91x(); |
194 | } | 192 | } |
195 | 193 | ||
196 | #ifdef CONFIG_ARCH_OMAP1510 | 194 | #ifdef CONFIG_ARCH_OMAP15XX |
197 | static struct omap_usb_config innovator1510_usb_config __initdata = { | 195 | static struct omap_usb_config innovator1510_usb_config __initdata = { |
198 | /* for bundled non-standard host and peripheral cables */ | 196 | /* for bundled non-standard host and peripheral cables */ |
199 | .hmc_mode = 4, | 197 | .hmc_mode = 4, |
@@ -205,6 +203,11 @@ static struct omap_usb_config innovator1510_usb_config __initdata = { | |||
205 | .register_dev = 1, | 203 | .register_dev = 1, |
206 | .pins[0] = 2, | 204 | .pins[0] = 2, |
207 | }; | 205 | }; |
206 | |||
207 | static struct omap_lcd_config innovator1510_lcd_config __initdata = { | ||
208 | .panel_name = "inn1510", | ||
209 | .ctrl_name = "internal", | ||
210 | }; | ||
208 | #endif | 211 | #endif |
209 | 212 | ||
210 | #ifdef CONFIG_ARCH_OMAP16XX | 213 | #ifdef CONFIG_ARCH_OMAP16XX |
@@ -222,6 +225,11 @@ static struct omap_usb_config h2_usb_config __initdata = { | |||
222 | 225 | ||
223 | .pins[1] = 3, | 226 | .pins[1] = 3, |
224 | }; | 227 | }; |
228 | |||
229 | static struct omap_lcd_config innovator1610_lcd_config __initdata = { | ||
230 | .panel_name = "inn1610", | ||
231 | .ctrl_name = "internal", | ||
232 | }; | ||
225 | #endif | 233 | #endif |
226 | 234 | ||
227 | static struct omap_mmc_config innovator_mmc_config __initdata = { | 235 | static struct omap_mmc_config innovator_mmc_config __initdata = { |
@@ -234,14 +242,20 @@ static struct omap_mmc_config innovator_mmc_config __initdata = { | |||
234 | }, | 242 | }, |
235 | }; | 243 | }; |
236 | 244 | ||
245 | static struct omap_uart_config innovator_uart_config __initdata = { | ||
246 | .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), | ||
247 | }; | ||
248 | |||
237 | static struct omap_board_config_kernel innovator_config[] = { | 249 | static struct omap_board_config_kernel innovator_config[] = { |
238 | { OMAP_TAG_USB, NULL }, | 250 | { OMAP_TAG_USB, NULL }, |
251 | { OMAP_TAG_LCD, NULL }, | ||
239 | { OMAP_TAG_MMC, &innovator_mmc_config }, | 252 | { OMAP_TAG_MMC, &innovator_mmc_config }, |
253 | { OMAP_TAG_UART, &innovator_uart_config }, | ||
240 | }; | 254 | }; |
241 | 255 | ||
242 | static void __init innovator_init(void) | 256 | static void __init innovator_init(void) |
243 | { | 257 | { |
244 | #ifdef CONFIG_ARCH_OMAP1510 | 258 | #ifdef CONFIG_ARCH_OMAP15XX |
245 | if (cpu_is_omap1510()) { | 259 | if (cpu_is_omap1510()) { |
246 | platform_add_devices(innovator1510_devices, ARRAY_SIZE(innovator1510_devices)); | 260 | platform_add_devices(innovator1510_devices, ARRAY_SIZE(innovator1510_devices)); |
247 | } | 261 | } |
@@ -252,23 +266,28 @@ static void __init innovator_init(void) | |||
252 | } | 266 | } |
253 | #endif | 267 | #endif |
254 | 268 | ||
255 | #ifdef CONFIG_ARCH_OMAP1510 | 269 | #ifdef CONFIG_ARCH_OMAP15XX |
256 | if (cpu_is_omap1510()) | 270 | if (cpu_is_omap1510()) { |
257 | innovator_config[0].data = &innovator1510_usb_config; | 271 | innovator_config[0].data = &innovator1510_usb_config; |
272 | innovator_config[1].data = &innovator1510_lcd_config; | ||
273 | } | ||
258 | #endif | 274 | #endif |
259 | #ifdef CONFIG_ARCH_OMAP16XX | 275 | #ifdef CONFIG_ARCH_OMAP16XX |
260 | if (cpu_is_omap1610()) | 276 | if (cpu_is_omap1610()) { |
261 | innovator_config[0].data = &h2_usb_config; | 277 | innovator_config[0].data = &h2_usb_config; |
278 | innovator_config[1].data = &innovator1610_lcd_config; | ||
279 | } | ||
262 | #endif | 280 | #endif |
263 | omap_board_config = innovator_config; | 281 | omap_board_config = innovator_config; |
264 | omap_board_config_size = ARRAY_SIZE(innovator_config); | 282 | omap_board_config_size = ARRAY_SIZE(innovator_config); |
283 | omap_serial_init(); | ||
265 | } | 284 | } |
266 | 285 | ||
267 | static void __init innovator_map_io(void) | 286 | static void __init innovator_map_io(void) |
268 | { | 287 | { |
269 | omap_map_common_io(); | 288 | omap_map_common_io(); |
270 | 289 | ||
271 | #ifdef CONFIG_ARCH_OMAP1510 | 290 | #ifdef CONFIG_ARCH_OMAP15XX |
272 | if (cpu_is_omap1510()) { | 291 | if (cpu_is_omap1510()) { |
273 | iotable_init(innovator1510_io_desc, ARRAY_SIZE(innovator1510_io_desc)); | 292 | iotable_init(innovator1510_io_desc, ARRAY_SIZE(innovator1510_io_desc)); |
274 | udelay(10); /* Delay needed for FPGA */ | 293 | udelay(10); /* Delay needed for FPGA */ |
@@ -280,7 +299,6 @@ static void __init innovator_map_io(void) | |||
280 | fpga_read(OMAP1510_FPGA_BOARD_REV)); | 299 | fpga_read(OMAP1510_FPGA_BOARD_REV)); |
281 | } | 300 | } |
282 | #endif | 301 | #endif |
283 | omap_serial_init(innovator_serial_ports); | ||
284 | } | 302 | } |
285 | 303 | ||
286 | MACHINE_START(OMAP_INNOVATOR, "TI-Innovator") | 304 | MACHINE_START(OMAP_INNOVATOR, "TI-Innovator") |
diff --git a/arch/arm/mach-omap1/board-netstar.c b/arch/arm/mach-omap1/board-netstar.c index c851c2e4dfcb..0448fa7de8a4 100644 --- a/arch/arm/mach-omap1/board-netstar.c +++ b/arch/arm/mach-omap1/board-netstar.c | |||
@@ -55,6 +55,14 @@ static struct platform_device *netstar_devices[] __initdata = { | |||
55 | &netstar_smc91x_device, | 55 | &netstar_smc91x_device, |
56 | }; | 56 | }; |
57 | 57 | ||
58 | static struct omap_uart_config netstar_uart_config __initdata = { | ||
59 | .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), | ||
60 | }; | ||
61 | |||
62 | static struct omap_board_config_kernel netstar_config[] = { | ||
63 | { OMAP_TAG_UART, &netstar_uart_config }, | ||
64 | }; | ||
65 | |||
58 | static void __init netstar_init_irq(void) | 66 | static void __init netstar_init_irq(void) |
59 | { | 67 | { |
60 | omap_init_irq(); | 68 | omap_init_irq(); |
@@ -92,14 +100,15 @@ static void __init netstar_init(void) | |||
92 | /* Switch off red LED */ | 100 | /* Switch off red LED */ |
93 | omap_writeb(0x00, OMAP_LPG1_PMR); /* Disable clock */ | 101 | omap_writeb(0x00, OMAP_LPG1_PMR); /* Disable clock */ |
94 | omap_writeb(0x80, OMAP_LPG1_LCR); | 102 | omap_writeb(0x80, OMAP_LPG1_LCR); |
95 | } | ||
96 | 103 | ||
97 | static int __initdata omap_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1}; | 104 | omap_board_config = netstar_config; |
105 | omap_board_config_size = ARRAY_SIZE(netstar_config); | ||
106 | omap_serial_init(); | ||
107 | } | ||
98 | 108 | ||
99 | static void __init netstar_map_io(void) | 109 | static void __init netstar_map_io(void) |
100 | { | 110 | { |
101 | omap_map_common_io(); | 111 | omap_map_common_io(); |
102 | omap_serial_init(omap_serial_ports); | ||
103 | } | 112 | } |
104 | 113 | ||
105 | #define MACHINE_PANICED 1 | 114 | #define MACHINE_PANICED 1 |
diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c index a88524e7c315..e990e1bc1669 100644 --- a/arch/arm/mach-omap1/board-osk.c +++ b/arch/arm/mach-omap1/board-osk.c | |||
@@ -46,8 +46,6 @@ | |||
46 | #include <asm/arch/tc.h> | 46 | #include <asm/arch/tc.h> |
47 | #include <asm/arch/common.h> | 47 | #include <asm/arch/common.h> |
48 | 48 | ||
49 | static int __initdata osk_serial_ports[OMAP_MAX_NR_PORTS] = {1, 0, 0}; | ||
50 | |||
51 | static struct mtd_partition osk_partitions[] = { | 49 | static struct mtd_partition osk_partitions[] = { |
52 | /* bootloader (U-Boot, etc) in first sector */ | 50 | /* bootloader (U-Boot, etc) in first sector */ |
53 | { | 51 | { |
@@ -155,7 +153,7 @@ static void __init osk_init_smc91x(void) | |||
155 | } | 153 | } |
156 | 154 | ||
157 | /* Check EMIFS wait states to fix errors with SMC_GET_PKT_HDR */ | 155 | /* Check EMIFS wait states to fix errors with SMC_GET_PKT_HDR */ |
158 | EMIFS_CCS(1) |= 0x2; | 156 | EMIFS_CCS(1) |= 0x3; |
159 | } | 157 | } |
160 | 158 | ||
161 | static void __init osk_init_cf(void) | 159 | static void __init osk_init_cf(void) |
@@ -193,8 +191,19 @@ static struct omap_usb_config osk_usb_config __initdata = { | |||
193 | .pins[0] = 2, | 191 | .pins[0] = 2, |
194 | }; | 192 | }; |
195 | 193 | ||
194 | static struct omap_uart_config osk_uart_config __initdata = { | ||
195 | .enabled_uarts = (1 << 0), | ||
196 | }; | ||
197 | |||
198 | static struct omap_lcd_config osk_lcd_config __initdata = { | ||
199 | .panel_name = "osk", | ||
200 | .ctrl_name = "internal", | ||
201 | }; | ||
202 | |||
196 | static struct omap_board_config_kernel osk_config[] = { | 203 | static struct omap_board_config_kernel osk_config[] = { |
197 | { OMAP_TAG_USB, &osk_usb_config }, | 204 | { OMAP_TAG_USB, &osk_usb_config }, |
205 | { OMAP_TAG_UART, &osk_uart_config }, | ||
206 | { OMAP_TAG_LCD, &osk_lcd_config }, | ||
198 | }; | 207 | }; |
199 | 208 | ||
200 | #ifdef CONFIG_OMAP_OSK_MISTRAL | 209 | #ifdef CONFIG_OMAP_OSK_MISTRAL |
@@ -254,13 +263,13 @@ static void __init osk_init(void) | |||
254 | omap_board_config_size = ARRAY_SIZE(osk_config); | 263 | omap_board_config_size = ARRAY_SIZE(osk_config); |
255 | USB_TRANSCEIVER_CTRL_REG |= (3 << 1); | 264 | USB_TRANSCEIVER_CTRL_REG |= (3 << 1); |
256 | 265 | ||
266 | omap_serial_init(); | ||
257 | osk_mistral_init(); | 267 | osk_mistral_init(); |
258 | } | 268 | } |
259 | 269 | ||
260 | static void __init osk_map_io(void) | 270 | static void __init osk_map_io(void) |
261 | { | 271 | { |
262 | omap_map_common_io(); | 272 | omap_map_common_io(); |
263 | omap_serial_init(osk_serial_ports); | ||
264 | } | 273 | } |
265 | 274 | ||
266 | MACHINE_START(OMAP_OSK, "TI-OSK") | 275 | MACHINE_START(OMAP_OSK, "TI-OSK") |
diff --git a/arch/arm/mach-omap1/board-palmte.c b/arch/arm/mach-omap1/board-palmte.c new file mode 100644 index 000000000000..540b20d78cca --- /dev/null +++ b/arch/arm/mach-omap1/board-palmte.c | |||
@@ -0,0 +1,87 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-omap1/board-palmte.c | ||
3 | * | ||
4 | * Modified from board-generic.c | ||
5 | * | ||
6 | * Support for the Palm Tungsten E PDA. | ||
7 | * | ||
8 | * Original version : Laurent Gonzalez | ||
9 | * | ||
10 | * Maintainters : http://palmtelinux.sf.net | ||
11 | * palmtelinux-developpers@lists.sf.net | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License version 2 as | ||
15 | * published by the Free Software Foundation. | ||
16 | */ | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/notifier.h> | ||
22 | |||
23 | #include <asm/hardware.h> | ||
24 | #include <asm/mach-types.h> | ||
25 | #include <asm/mach/arch.h> | ||
26 | #include <asm/mach/map.h> | ||
27 | |||
28 | #include <asm/arch/gpio.h> | ||
29 | #include <asm/arch/mux.h> | ||
30 | #include <asm/arch/usb.h> | ||
31 | #include <asm/arch/board.h> | ||
32 | #include <asm/arch/common.h> | ||
33 | #include <asm/hardware/clock.h> | ||
34 | |||
35 | static void __init omap_generic_init_irq(void) | ||
36 | { | ||
37 | omap_init_irq(); | ||
38 | } | ||
39 | |||
40 | static struct omap_usb_config palmte_usb_config __initdata = { | ||
41 | .register_dev = 1, | ||
42 | .hmc_mode = 0, | ||
43 | .pins[0] = 3, | ||
44 | }; | ||
45 | |||
46 | static struct omap_mmc_config palmte_mmc_config __initdata = { | ||
47 | .mmc [0] = { | ||
48 | .enabled = 1, | ||
49 | .wire4 = 1, | ||
50 | .wp_pin = OMAP_MPUIO(3), | ||
51 | .power_pin = -1, | ||
52 | .switch_pin = -1, | ||
53 | }, | ||
54 | }; | ||
55 | |||
56 | static struct omap_lcd_config palmte_lcd_config __initdata = { | ||
57 | .panel_name = "palmte", | ||
58 | .ctrl_name = "internal", | ||
59 | }; | ||
60 | |||
61 | static struct omap_board_config_kernel palmte_config[] = { | ||
62 | { OMAP_TAG_USB, &palmte_usb_config }, | ||
63 | { OMAP_TAG_MMC, &palmte_mmc_config }, | ||
64 | { OMAP_TAG_LCD, &palmte_lcd_config }, | ||
65 | }; | ||
66 | |||
67 | static void __init omap_generic_init(void) | ||
68 | { | ||
69 | omap_board_config = palmte_config; | ||
70 | omap_board_config_size = ARRAY_SIZE(palmte_config); | ||
71 | } | ||
72 | |||
73 | static void __init omap_generic_map_io(void) | ||
74 | { | ||
75 | omap_map_common_io(); | ||
76 | } | ||
77 | |||
78 | MACHINE_START(OMAP_PALMTE, "OMAP310 based Palm Tungsten E") | ||
79 | .phys_ram = 0x10000000, | ||
80 | .phys_io = 0xfff00000, | ||
81 | .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc, | ||
82 | .boot_params = 0x10000100, | ||
83 | .map_io = omap_generic_map_io, | ||
84 | .init_irq = omap_generic_init_irq, | ||
85 | .init_machine = omap_generic_init, | ||
86 | .timer = &omap_timer, | ||
87 | MACHINE_END | ||
diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c index 354b157acb3a..bd900b7ab33c 100644 --- a/arch/arm/mach-omap1/board-perseus2.c +++ b/arch/arm/mach-omap1/board-perseus2.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <asm/arch/mux.h> | 29 | #include <asm/arch/mux.h> |
30 | #include <asm/arch/fpga.h> | 30 | #include <asm/arch/fpga.h> |
31 | #include <asm/arch/common.h> | 31 | #include <asm/arch/common.h> |
32 | #include <asm/arch/board.h> | ||
32 | 33 | ||
33 | static struct resource smc91x_resources[] = { | 34 | static struct resource smc91x_resources[] = { |
34 | [0] = { | 35 | [0] = { |
@@ -43,8 +44,6 @@ static struct resource smc91x_resources[] = { | |||
43 | }, | 44 | }, |
44 | }; | 45 | }; |
45 | 46 | ||
46 | static int __initdata p2_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 0}; | ||
47 | |||
48 | static struct mtd_partition p2_partitions[] = { | 47 | static struct mtd_partition p2_partitions[] = { |
49 | /* bootloader (U-Boot, etc) in first sector */ | 48 | /* bootloader (U-Boot, etc) in first sector */ |
50 | { | 49 | { |
@@ -111,9 +110,27 @@ static struct platform_device *devices[] __initdata = { | |||
111 | &smc91x_device, | 110 | &smc91x_device, |
112 | }; | 111 | }; |
113 | 112 | ||
113 | static struct omap_uart_config perseus2_uart_config __initdata = { | ||
114 | .enabled_uarts = ((1 << 0) | (1 << 1)), | ||
115 | }; | ||
116 | |||
117 | static struct omap_lcd_config perseus2_lcd_config __initdata = { | ||
118 | .panel_name = "p2", | ||
119 | .ctrl_name = "internal", | ||
120 | }; | ||
121 | |||
122 | static struct omap_board_config_kernel perseus2_config[] = { | ||
123 | { OMAP_TAG_UART, &perseus2_uart_config }, | ||
124 | { OMAP_TAG_LCD, &perseus2_lcd_config }, | ||
125 | }; | ||
126 | |||
114 | static void __init omap_perseus2_init(void) | 127 | static void __init omap_perseus2_init(void) |
115 | { | 128 | { |
116 | (void) platform_add_devices(devices, ARRAY_SIZE(devices)); | 129 | (void) platform_add_devices(devices, ARRAY_SIZE(devices)); |
130 | |||
131 | omap_board_config = perseus2_config; | ||
132 | omap_board_config_size = ARRAY_SIZE(perseus2_config); | ||
133 | omap_serial_init(); | ||
117 | } | 134 | } |
118 | 135 | ||
119 | static void __init perseus2_init_smc91x(void) | 136 | static void __init perseus2_init_smc91x(void) |
@@ -131,7 +148,6 @@ void omap_perseus2_init_irq(void) | |||
131 | omap_gpio_init(); | 148 | omap_gpio_init(); |
132 | perseus2_init_smc91x(); | 149 | perseus2_init_smc91x(); |
133 | } | 150 | } |
134 | |||
135 | /* Only FPGA needs to be mapped here. All others are done with ioremap */ | 151 | /* Only FPGA needs to be mapped here. All others are done with ioremap */ |
136 | static struct map_desc omap_perseus2_io_desc[] __initdata = { | 152 | static struct map_desc omap_perseus2_io_desc[] __initdata = { |
137 | { | 153 | { |
@@ -179,7 +195,6 @@ static void __init omap_perseus2_map_io(void) | |||
179 | * It is used as the Ethernet controller interrupt | 195 | * It is used as the Ethernet controller interrupt |
180 | */ | 196 | */ |
181 | omap_writel(omap_readl(OMAP730_IO_CONF_9) & 0x1FFFFFFF, OMAP730_IO_CONF_9); | 197 | omap_writel(omap_readl(OMAP730_IO_CONF_9) & 0x1FFFFFFF, OMAP730_IO_CONF_9); |
182 | omap_serial_init(p2_serial_ports); | ||
183 | } | 198 | } |
184 | 199 | ||
185 | MACHINE_START(OMAP_PERSEUS2, "OMAP730 Perseus2") | 200 | MACHINE_START(OMAP_PERSEUS2, "OMAP730 Perseus2") |
diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c index 3f018b296861..6f9a6220e78a 100644 --- a/arch/arm/mach-omap1/board-voiceblue.c +++ b/arch/arm/mach-omap1/board-voiceblue.c | |||
@@ -150,9 +150,14 @@ static struct omap_mmc_config voiceblue_mmc_config __initdata = { | |||
150 | }, | 150 | }, |
151 | }; | 151 | }; |
152 | 152 | ||
153 | static struct omap_uart_config voiceblue_uart_config __initdata = { | ||
154 | .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), | ||
155 | }; | ||
156 | |||
153 | static struct omap_board_config_kernel voiceblue_config[] = { | 157 | static struct omap_board_config_kernel voiceblue_config[] = { |
154 | { OMAP_TAG_USB, &voiceblue_usb_config }, | 158 | { OMAP_TAG_USB, &voiceblue_usb_config }, |
155 | { OMAP_TAG_MMC, &voiceblue_mmc_config }, | 159 | { OMAP_TAG_MMC, &voiceblue_mmc_config }, |
160 | { OMAP_TAG_UART, &voiceblue_uart_config }, | ||
156 | }; | 161 | }; |
157 | 162 | ||
158 | static void __init voiceblue_init_irq(void) | 163 | static void __init voiceblue_init_irq(void) |
@@ -191,6 +196,7 @@ static void __init voiceblue_init(void) | |||
191 | platform_add_devices(voiceblue_devices, ARRAY_SIZE(voiceblue_devices)); | 196 | platform_add_devices(voiceblue_devices, ARRAY_SIZE(voiceblue_devices)); |
192 | omap_board_config = voiceblue_config; | 197 | omap_board_config = voiceblue_config; |
193 | omap_board_config_size = ARRAY_SIZE(voiceblue_config); | 198 | omap_board_config_size = ARRAY_SIZE(voiceblue_config); |
199 | omap_serial_init(); | ||
194 | 200 | ||
195 | /* There is a good chance board is going up, so enable power LED | 201 | /* There is a good chance board is going up, so enable power LED |
196 | * (it is connected through invertor) */ | 202 | * (it is connected through invertor) */ |
@@ -198,12 +204,9 @@ static void __init voiceblue_init(void) | |||
198 | omap_writeb(0x00, OMAP_LPG1_PMR); /* Disable clock */ | 204 | omap_writeb(0x00, OMAP_LPG1_PMR); /* Disable clock */ |
199 | } | 205 | } |
200 | 206 | ||
201 | static int __initdata omap_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1}; | ||
202 | |||
203 | static void __init voiceblue_map_io(void) | 207 | static void __init voiceblue_map_io(void) |
204 | { | 208 | { |
205 | omap_map_common_io(); | 209 | omap_map_common_io(); |
206 | omap_serial_init(omap_serial_ports); | ||
207 | } | 210 | } |
208 | 211 | ||
209 | #define MACHINE_PANICED 1 | 212 | #define MACHINE_PANICED 1 |
diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c new file mode 100644 index 000000000000..4277eee44ed5 --- /dev/null +++ b/arch/arm/mach-omap1/clock.c | |||
@@ -0,0 +1,792 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-omap1/clock.c | ||
3 | * | ||
4 | * Copyright (C) 2004 - 2005 Nokia corporation | ||
5 | * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> | ||
6 | * | ||
7 | * Modified to use omap shared clock framework by | ||
8 | * Tony Lindgren <tony@atomide.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/list.h> | ||
17 | #include <linux/errno.h> | ||
18 | #include <linux/err.h> | ||
19 | |||
20 | #include <asm/io.h> | ||
21 | #include <asm/hardware/clock.h> | ||
22 | |||
23 | #include <asm/arch/usb.h> | ||
24 | #include <asm/arch/clock.h> | ||
25 | #include <asm/arch/sram.h> | ||
26 | |||
27 | #include "clock.h" | ||
28 | |||
29 | __u32 arm_idlect1_mask; | ||
30 | |||
31 | /*------------------------------------------------------------------------- | ||
32 | * Omap1 specific clock functions | ||
33 | *-------------------------------------------------------------------------*/ | ||
34 | |||
35 | static void omap1_watchdog_recalc(struct clk * clk) | ||
36 | { | ||
37 | clk->rate = clk->parent->rate / 14; | ||
38 | } | ||
39 | |||
40 | static void omap1_uart_recalc(struct clk * clk) | ||
41 | { | ||
42 | unsigned int val = omap_readl(clk->enable_reg); | ||
43 | if (val & clk->enable_bit) | ||
44 | clk->rate = 48000000; | ||
45 | else | ||
46 | clk->rate = 12000000; | ||
47 | } | ||
48 | |||
49 | static int omap1_clk_enable_dsp_domain(struct clk *clk) | ||
50 | { | ||
51 | int retval; | ||
52 | |||
53 | retval = omap1_clk_use(&api_ck.clk); | ||
54 | if (!retval) { | ||
55 | retval = omap1_clk_enable(clk); | ||
56 | omap1_clk_unuse(&api_ck.clk); | ||
57 | } | ||
58 | |||
59 | return retval; | ||
60 | } | ||
61 | |||
62 | static void omap1_clk_disable_dsp_domain(struct clk *clk) | ||
63 | { | ||
64 | if (omap1_clk_use(&api_ck.clk) == 0) { | ||
65 | omap1_clk_disable(clk); | ||
66 | omap1_clk_unuse(&api_ck.clk); | ||
67 | } | ||
68 | } | ||
69 | |||
70 | static int omap1_clk_enable_uart_functional(struct clk *clk) | ||
71 | { | ||
72 | int ret; | ||
73 | struct uart_clk *uclk; | ||
74 | |||
75 | ret = omap1_clk_enable(clk); | ||
76 | if (ret == 0) { | ||
77 | /* Set smart idle acknowledgement mode */ | ||
78 | uclk = (struct uart_clk *)clk; | ||
79 | omap_writeb((omap_readb(uclk->sysc_addr) & ~0x10) | 8, | ||
80 | uclk->sysc_addr); | ||
81 | } | ||
82 | |||
83 | return ret; | ||
84 | } | ||
85 | |||
86 | static void omap1_clk_disable_uart_functional(struct clk *clk) | ||
87 | { | ||
88 | struct uart_clk *uclk; | ||
89 | |||
90 | /* Set force idle acknowledgement mode */ | ||
91 | uclk = (struct uart_clk *)clk; | ||
92 | omap_writeb((omap_readb(uclk->sysc_addr) & ~0x18), uclk->sysc_addr); | ||
93 | |||
94 | omap1_clk_disable(clk); | ||
95 | } | ||
96 | |||
97 | static void omap1_clk_allow_idle(struct clk *clk) | ||
98 | { | ||
99 | struct arm_idlect1_clk * iclk = (struct arm_idlect1_clk *)clk; | ||
100 | |||
101 | if (!(clk->flags & CLOCK_IDLE_CONTROL)) | ||
102 | return; | ||
103 | |||
104 | if (iclk->no_idle_count > 0 && !(--iclk->no_idle_count)) | ||
105 | arm_idlect1_mask |= 1 << iclk->idlect_shift; | ||
106 | } | ||
107 | |||
108 | static void omap1_clk_deny_idle(struct clk *clk) | ||
109 | { | ||
110 | struct arm_idlect1_clk * iclk = (struct arm_idlect1_clk *)clk; | ||
111 | |||
112 | if (!(clk->flags & CLOCK_IDLE_CONTROL)) | ||
113 | return; | ||
114 | |||
115 | if (iclk->no_idle_count++ == 0) | ||
116 | arm_idlect1_mask &= ~(1 << iclk->idlect_shift); | ||
117 | } | ||
118 | |||
119 | static __u16 verify_ckctl_value(__u16 newval) | ||
120 | { | ||
121 | /* This function checks for following limitations set | ||
122 | * by the hardware (all conditions must be true): | ||
123 | * DSPMMU_CK == DSP_CK or DSPMMU_CK == DSP_CK/2 | ||
124 | * ARM_CK >= TC_CK | ||
125 | * DSP_CK >= TC_CK | ||
126 | * DSPMMU_CK >= TC_CK | ||
127 | * | ||
128 | * In addition following rules are enforced: | ||
129 | * LCD_CK <= TC_CK | ||
130 | * ARMPER_CK <= TC_CK | ||
131 | * | ||
132 | * However, maximum frequencies are not checked for! | ||
133 | */ | ||
134 | __u8 per_exp; | ||
135 | __u8 lcd_exp; | ||
136 | __u8 arm_exp; | ||
137 | __u8 dsp_exp; | ||
138 | __u8 tc_exp; | ||
139 | __u8 dspmmu_exp; | ||
140 | |||
141 | per_exp = (newval >> CKCTL_PERDIV_OFFSET) & 3; | ||
142 | lcd_exp = (newval >> CKCTL_LCDDIV_OFFSET) & 3; | ||
143 | arm_exp = (newval >> CKCTL_ARMDIV_OFFSET) & 3; | ||
144 | dsp_exp = (newval >> CKCTL_DSPDIV_OFFSET) & 3; | ||
145 | tc_exp = (newval >> CKCTL_TCDIV_OFFSET) & 3; | ||
146 | dspmmu_exp = (newval >> CKCTL_DSPMMUDIV_OFFSET) & 3; | ||
147 | |||
148 | if (dspmmu_exp < dsp_exp) | ||
149 | dspmmu_exp = dsp_exp; | ||
150 | if (dspmmu_exp > dsp_exp+1) | ||
151 | dspmmu_exp = dsp_exp+1; | ||
152 | if (tc_exp < arm_exp) | ||
153 | tc_exp = arm_exp; | ||
154 | if (tc_exp < dspmmu_exp) | ||
155 | tc_exp = dspmmu_exp; | ||
156 | if (tc_exp > lcd_exp) | ||
157 | lcd_exp = tc_exp; | ||
158 | if (tc_exp > per_exp) | ||
159 | per_exp = tc_exp; | ||
160 | |||
161 | newval &= 0xf000; | ||
162 | newval |= per_exp << CKCTL_PERDIV_OFFSET; | ||
163 | newval |= lcd_exp << CKCTL_LCDDIV_OFFSET; | ||
164 | newval |= arm_exp << CKCTL_ARMDIV_OFFSET; | ||
165 | newval |= dsp_exp << CKCTL_DSPDIV_OFFSET; | ||
166 | newval |= tc_exp << CKCTL_TCDIV_OFFSET; | ||
167 | newval |= dspmmu_exp << CKCTL_DSPMMUDIV_OFFSET; | ||
168 | |||
169 | return newval; | ||
170 | } | ||
171 | |||
172 | static int calc_dsor_exp(struct clk *clk, unsigned long rate) | ||
173 | { | ||
174 | /* Note: If target frequency is too low, this function will return 4, | ||
175 | * which is invalid value. Caller must check for this value and act | ||
176 | * accordingly. | ||
177 | * | ||
178 | * Note: This function does not check for following limitations set | ||
179 | * by the hardware (all conditions must be true): | ||
180 | * DSPMMU_CK == DSP_CK or DSPMMU_CK == DSP_CK/2 | ||
181 | * ARM_CK >= TC_CK | ||
182 | * DSP_CK >= TC_CK | ||
183 | * DSPMMU_CK >= TC_CK | ||
184 | */ | ||
185 | unsigned long realrate; | ||
186 | struct clk * parent; | ||
187 | unsigned dsor_exp; | ||
188 | |||
189 | if (unlikely(!(clk->flags & RATE_CKCTL))) | ||
190 | return -EINVAL; | ||
191 | |||
192 | parent = clk->parent; | ||
193 | if (unlikely(parent == 0)) | ||
194 | return -EIO; | ||
195 | |||
196 | realrate = parent->rate; | ||
197 | for (dsor_exp=0; dsor_exp<4; dsor_exp++) { | ||
198 | if (realrate <= rate) | ||
199 | break; | ||
200 | |||
201 | realrate /= 2; | ||
202 | } | ||
203 | |||
204 | return dsor_exp; | ||
205 | } | ||
206 | |||
207 | static void omap1_ckctl_recalc(struct clk * clk) | ||
208 | { | ||
209 | int dsor; | ||
210 | |||
211 | /* Calculate divisor encoded as 2-bit exponent */ | ||
212 | dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset)); | ||
213 | |||
214 | if (unlikely(clk->rate == clk->parent->rate / dsor)) | ||
215 | return; /* No change, quick exit */ | ||
216 | clk->rate = clk->parent->rate / dsor; | ||
217 | |||
218 | if (unlikely(clk->flags & RATE_PROPAGATES)) | ||
219 | propagate_rate(clk); | ||
220 | } | ||
221 | |||
222 | static void omap1_ckctl_recalc_dsp_domain(struct clk * clk) | ||
223 | { | ||
224 | int dsor; | ||
225 | |||
226 | /* Calculate divisor encoded as 2-bit exponent | ||
227 | * | ||
228 | * The clock control bits are in DSP domain, | ||
229 | * so api_ck is needed for access. | ||
230 | * Note that DSP_CKCTL virt addr = phys addr, so | ||
231 | * we must use __raw_readw() instead of omap_readw(). | ||
232 | */ | ||
233 | omap1_clk_use(&api_ck.clk); | ||
234 | dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset)); | ||
235 | omap1_clk_unuse(&api_ck.clk); | ||
236 | |||
237 | if (unlikely(clk->rate == clk->parent->rate / dsor)) | ||
238 | return; /* No change, quick exit */ | ||
239 | clk->rate = clk->parent->rate / dsor; | ||
240 | |||
241 | if (unlikely(clk->flags & RATE_PROPAGATES)) | ||
242 | propagate_rate(clk); | ||
243 | } | ||
244 | |||
245 | /* MPU virtual clock functions */ | ||
246 | static int omap1_select_table_rate(struct clk * clk, unsigned long rate) | ||
247 | { | ||
248 | /* Find the highest supported frequency <= rate and switch to it */ | ||
249 | struct mpu_rate * ptr; | ||
250 | |||
251 | if (clk != &virtual_ck_mpu) | ||
252 | return -EINVAL; | ||
253 | |||
254 | for (ptr = rate_table; ptr->rate; ptr++) { | ||
255 | if (ptr->xtal != ck_ref.rate) | ||
256 | continue; | ||
257 | |||
258 | /* DPLL1 cannot be reprogrammed without risking system crash */ | ||
259 | if (likely(ck_dpll1.rate!=0) && ptr->pll_rate != ck_dpll1.rate) | ||
260 | continue; | ||
261 | |||
262 | /* Can check only after xtal frequency check */ | ||
263 | if (ptr->rate <= rate) | ||
264 | break; | ||
265 | } | ||
266 | |||
267 | if (!ptr->rate) | ||
268 | return -EINVAL; | ||
269 | |||
270 | /* | ||
271 | * In most cases we should not need to reprogram DPLL. | ||
272 | * Reprogramming the DPLL is tricky, it must be done from SRAM. | ||
273 | */ | ||
274 | omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val); | ||
275 | |||
276 | ck_dpll1.rate = ptr->pll_rate; | ||
277 | propagate_rate(&ck_dpll1); | ||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | static int omap1_clk_set_rate_dsp_domain(struct clk *clk, unsigned long rate) | ||
282 | { | ||
283 | int ret = -EINVAL; | ||
284 | int dsor_exp; | ||
285 | __u16 regval; | ||
286 | |||
287 | if (clk->flags & RATE_CKCTL) { | ||
288 | dsor_exp = calc_dsor_exp(clk, rate); | ||
289 | if (dsor_exp > 3) | ||
290 | dsor_exp = -EINVAL; | ||
291 | if (dsor_exp < 0) | ||
292 | return dsor_exp; | ||
293 | |||
294 | regval = __raw_readw(DSP_CKCTL); | ||
295 | regval &= ~(3 << clk->rate_offset); | ||
296 | regval |= dsor_exp << clk->rate_offset; | ||
297 | __raw_writew(regval, DSP_CKCTL); | ||
298 | clk->rate = clk->parent->rate / (1 << dsor_exp); | ||
299 | ret = 0; | ||
300 | } | ||
301 | |||
302 | if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES))) | ||
303 | propagate_rate(clk); | ||
304 | |||
305 | return ret; | ||
306 | } | ||
307 | |||
308 | static long omap1_round_to_table_rate(struct clk * clk, unsigned long rate) | ||
309 | { | ||
310 | /* Find the highest supported frequency <= rate */ | ||
311 | struct mpu_rate * ptr; | ||
312 | long highest_rate; | ||
313 | |||
314 | if (clk != &virtual_ck_mpu) | ||
315 | return -EINVAL; | ||
316 | |||
317 | highest_rate = -EINVAL; | ||
318 | |||
319 | for (ptr = rate_table; ptr->rate; ptr++) { | ||
320 | if (ptr->xtal != ck_ref.rate) | ||
321 | continue; | ||
322 | |||
323 | highest_rate = ptr->rate; | ||
324 | |||
325 | /* Can check only after xtal frequency check */ | ||
326 | if (ptr->rate <= rate) | ||
327 | break; | ||
328 | } | ||
329 | |||
330 | return highest_rate; | ||
331 | } | ||
332 | |||
333 | static unsigned calc_ext_dsor(unsigned long rate) | ||
334 | { | ||
335 | unsigned dsor; | ||
336 | |||
337 | /* MCLK and BCLK divisor selection is not linear: | ||
338 | * freq = 96MHz / dsor | ||
339 | * | ||
340 | * RATIO_SEL range: dsor <-> RATIO_SEL | ||
341 | * 0..6: (RATIO_SEL+2) <-> (dsor-2) | ||
342 | * 6..48: (8+(RATIO_SEL-6)*2) <-> ((dsor-8)/2+6) | ||
343 | * Minimum dsor is 2 and maximum is 96. Odd divisors starting from 9 | ||
344 | * can not be used. | ||
345 | */ | ||
346 | for (dsor = 2; dsor < 96; ++dsor) { | ||
347 | if ((dsor & 1) && dsor > 8) | ||
348 | continue; | ||
349 | if (rate >= 96000000 / dsor) | ||
350 | break; | ||
351 | } | ||
352 | return dsor; | ||
353 | } | ||
354 | |||
355 | /* Only needed on 1510 */ | ||
356 | static int omap1_set_uart_rate(struct clk * clk, unsigned long rate) | ||
357 | { | ||
358 | unsigned int val; | ||
359 | |||
360 | val = omap_readl(clk->enable_reg); | ||
361 | if (rate == 12000000) | ||
362 | val &= ~(1 << clk->enable_bit); | ||
363 | else if (rate == 48000000) | ||
364 | val |= (1 << clk->enable_bit); | ||
365 | else | ||
366 | return -EINVAL; | ||
367 | omap_writel(val, clk->enable_reg); | ||
368 | clk->rate = rate; | ||
369 | |||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | /* External clock (MCLK & BCLK) functions */ | ||
374 | static int omap1_set_ext_clk_rate(struct clk * clk, unsigned long rate) | ||
375 | { | ||
376 | unsigned dsor; | ||
377 | __u16 ratio_bits; | ||
378 | |||
379 | dsor = calc_ext_dsor(rate); | ||
380 | clk->rate = 96000000 / dsor; | ||
381 | if (dsor > 8) | ||
382 | ratio_bits = ((dsor - 8) / 2 + 6) << 2; | ||
383 | else | ||
384 | ratio_bits = (dsor - 2) << 2; | ||
385 | |||
386 | ratio_bits |= omap_readw(clk->enable_reg) & ~0xfd; | ||
387 | omap_writew(ratio_bits, clk->enable_reg); | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | static long omap1_round_ext_clk_rate(struct clk * clk, unsigned long rate) | ||
393 | { | ||
394 | return 96000000 / calc_ext_dsor(rate); | ||
395 | } | ||
396 | |||
397 | static void omap1_init_ext_clk(struct clk * clk) | ||
398 | { | ||
399 | unsigned dsor; | ||
400 | __u16 ratio_bits; | ||
401 | |||
402 | /* Determine current rate and ensure clock is based on 96MHz APLL */ | ||
403 | ratio_bits = omap_readw(clk->enable_reg) & ~1; | ||
404 | omap_writew(ratio_bits, clk->enable_reg); | ||
405 | |||
406 | ratio_bits = (ratio_bits & 0xfc) >> 2; | ||
407 | if (ratio_bits > 6) | ||
408 | dsor = (ratio_bits - 6) * 2 + 8; | ||
409 | else | ||
410 | dsor = ratio_bits + 2; | ||
411 | |||
412 | clk-> rate = 96000000 / dsor; | ||
413 | } | ||
414 | |||
415 | static int omap1_clk_use(struct clk *clk) | ||
416 | { | ||
417 | int ret = 0; | ||
418 | if (clk->usecount++ == 0) { | ||
419 | if (likely(clk->parent)) { | ||
420 | ret = omap1_clk_use(clk->parent); | ||
421 | |||
422 | if (unlikely(ret != 0)) { | ||
423 | clk->usecount--; | ||
424 | return ret; | ||
425 | } | ||
426 | |||
427 | if (clk->flags & CLOCK_NO_IDLE_PARENT) | ||
428 | if (!cpu_is_omap24xx()) | ||
429 | omap1_clk_deny_idle(clk->parent); | ||
430 | } | ||
431 | |||
432 | ret = clk->enable(clk); | ||
433 | |||
434 | if (unlikely(ret != 0) && clk->parent) { | ||
435 | omap1_clk_unuse(clk->parent); | ||
436 | clk->usecount--; | ||
437 | } | ||
438 | } | ||
439 | |||
440 | return ret; | ||
441 | } | ||
442 | |||
443 | static void omap1_clk_unuse(struct clk *clk) | ||
444 | { | ||
445 | if (clk->usecount > 0 && !(--clk->usecount)) { | ||
446 | clk->disable(clk); | ||
447 | if (likely(clk->parent)) { | ||
448 | omap1_clk_unuse(clk->parent); | ||
449 | if (clk->flags & CLOCK_NO_IDLE_PARENT) | ||
450 | if (!cpu_is_omap24xx()) | ||
451 | omap1_clk_allow_idle(clk->parent); | ||
452 | } | ||
453 | } | ||
454 | } | ||
455 | |||
456 | static int omap1_clk_enable(struct clk *clk) | ||
457 | { | ||
458 | __u16 regval16; | ||
459 | __u32 regval32; | ||
460 | |||
461 | if (clk->flags & ALWAYS_ENABLED) | ||
462 | return 0; | ||
463 | |||
464 | if (unlikely(clk->enable_reg == 0)) { | ||
465 | printk(KERN_ERR "clock.c: Enable for %s without enable code\n", | ||
466 | clk->name); | ||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | if (clk->flags & ENABLE_REG_32BIT) { | ||
471 | if (clk->flags & VIRTUAL_IO_ADDRESS) { | ||
472 | regval32 = __raw_readl(clk->enable_reg); | ||
473 | regval32 |= (1 << clk->enable_bit); | ||
474 | __raw_writel(regval32, clk->enable_reg); | ||
475 | } else { | ||
476 | regval32 = omap_readl(clk->enable_reg); | ||
477 | regval32 |= (1 << clk->enable_bit); | ||
478 | omap_writel(regval32, clk->enable_reg); | ||
479 | } | ||
480 | } else { | ||
481 | if (clk->flags & VIRTUAL_IO_ADDRESS) { | ||
482 | regval16 = __raw_readw(clk->enable_reg); | ||
483 | regval16 |= (1 << clk->enable_bit); | ||
484 | __raw_writew(regval16, clk->enable_reg); | ||
485 | } else { | ||
486 | regval16 = omap_readw(clk->enable_reg); | ||
487 | regval16 |= (1 << clk->enable_bit); | ||
488 | omap_writew(regval16, clk->enable_reg); | ||
489 | } | ||
490 | } | ||
491 | |||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | static void omap1_clk_disable(struct clk *clk) | ||
496 | { | ||
497 | __u16 regval16; | ||
498 | __u32 regval32; | ||
499 | |||
500 | if (clk->enable_reg == 0) | ||
501 | return; | ||
502 | |||
503 | if (clk->flags & ENABLE_REG_32BIT) { | ||
504 | if (clk->flags & VIRTUAL_IO_ADDRESS) { | ||
505 | regval32 = __raw_readl(clk->enable_reg); | ||
506 | regval32 &= ~(1 << clk->enable_bit); | ||
507 | __raw_writel(regval32, clk->enable_reg); | ||
508 | } else { | ||
509 | regval32 = omap_readl(clk->enable_reg); | ||
510 | regval32 &= ~(1 << clk->enable_bit); | ||
511 | omap_writel(regval32, clk->enable_reg); | ||
512 | } | ||
513 | } else { | ||
514 | if (clk->flags & VIRTUAL_IO_ADDRESS) { | ||
515 | regval16 = __raw_readw(clk->enable_reg); | ||
516 | regval16 &= ~(1 << clk->enable_bit); | ||
517 | __raw_writew(regval16, clk->enable_reg); | ||
518 | } else { | ||
519 | regval16 = omap_readw(clk->enable_reg); | ||
520 | regval16 &= ~(1 << clk->enable_bit); | ||
521 | omap_writew(regval16, clk->enable_reg); | ||
522 | } | ||
523 | } | ||
524 | } | ||
525 | |||
526 | static long omap1_clk_round_rate(struct clk *clk, unsigned long rate) | ||
527 | { | ||
528 | int dsor_exp; | ||
529 | |||
530 | if (clk->flags & RATE_FIXED) | ||
531 | return clk->rate; | ||
532 | |||
533 | if (clk->flags & RATE_CKCTL) { | ||
534 | dsor_exp = calc_dsor_exp(clk, rate); | ||
535 | if (dsor_exp < 0) | ||
536 | return dsor_exp; | ||
537 | if (dsor_exp > 3) | ||
538 | dsor_exp = 3; | ||
539 | return clk->parent->rate / (1 << dsor_exp); | ||
540 | } | ||
541 | |||
542 | if(clk->round_rate != 0) | ||
543 | return clk->round_rate(clk, rate); | ||
544 | |||
545 | return clk->rate; | ||
546 | } | ||
547 | |||
548 | static int omap1_clk_set_rate(struct clk *clk, unsigned long rate) | ||
549 | { | ||
550 | int ret = -EINVAL; | ||
551 | int dsor_exp; | ||
552 | __u16 regval; | ||
553 | |||
554 | if (clk->set_rate) | ||
555 | ret = clk->set_rate(clk, rate); | ||
556 | else if (clk->flags & RATE_CKCTL) { | ||
557 | dsor_exp = calc_dsor_exp(clk, rate); | ||
558 | if (dsor_exp > 3) | ||
559 | dsor_exp = -EINVAL; | ||
560 | if (dsor_exp < 0) | ||
561 | return dsor_exp; | ||
562 | |||
563 | regval = omap_readw(ARM_CKCTL); | ||
564 | regval &= ~(3 << clk->rate_offset); | ||
565 | regval |= dsor_exp << clk->rate_offset; | ||
566 | regval = verify_ckctl_value(regval); | ||
567 | omap_writew(regval, ARM_CKCTL); | ||
568 | clk->rate = clk->parent->rate / (1 << dsor_exp); | ||
569 | ret = 0; | ||
570 | } | ||
571 | |||
572 | if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES))) | ||
573 | propagate_rate(clk); | ||
574 | |||
575 | return ret; | ||
576 | } | ||
577 | |||
578 | /*------------------------------------------------------------------------- | ||
579 | * Omap1 clock reset and init functions | ||
580 | *-------------------------------------------------------------------------*/ | ||
581 | |||
582 | #ifdef CONFIG_OMAP_RESET_CLOCKS | ||
583 | /* | ||
584 | * Resets some clocks that may be left on from bootloader, | ||
585 | * but leaves serial clocks on. See also omap_late_clk_reset(). | ||
586 | */ | ||
587 | static inline void omap1_early_clk_reset(void) | ||
588 | { | ||
589 | //omap_writel(0x3 << 29, MOD_CONF_CTRL_0); | ||
590 | } | ||
591 | |||
592 | static int __init omap1_late_clk_reset(void) | ||
593 | { | ||
594 | /* Turn off all unused clocks */ | ||
595 | struct clk *p; | ||
596 | __u32 regval32; | ||
597 | |||
598 | /* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */ | ||
599 | regval32 = omap_readw(SOFT_REQ_REG) & (1 << 4); | ||
600 | omap_writew(regval32, SOFT_REQ_REG); | ||
601 | omap_writew(0, SOFT_REQ_REG2); | ||
602 | |||
603 | list_for_each_entry(p, &clocks, node) { | ||
604 | if (p->usecount > 0 || (p->flags & ALWAYS_ENABLED) || | ||
605 | p->enable_reg == 0) | ||
606 | continue; | ||
607 | |||
608 | /* Clocks in the DSP domain need api_ck. Just assume bootloader | ||
609 | * has not enabled any DSP clocks */ | ||
610 | if ((u32)p->enable_reg == DSP_IDLECT2) { | ||
611 | printk(KERN_INFO "Skipping reset check for DSP domain " | ||
612 | "clock \"%s\"\n", p->name); | ||
613 | continue; | ||
614 | } | ||
615 | |||
616 | /* Is the clock already disabled? */ | ||
617 | if (p->flags & ENABLE_REG_32BIT) { | ||
618 | if (p->flags & VIRTUAL_IO_ADDRESS) | ||
619 | regval32 = __raw_readl(p->enable_reg); | ||
620 | else | ||
621 | regval32 = omap_readl(p->enable_reg); | ||
622 | } else { | ||
623 | if (p->flags & VIRTUAL_IO_ADDRESS) | ||
624 | regval32 = __raw_readw(p->enable_reg); | ||
625 | else | ||
626 | regval32 = omap_readw(p->enable_reg); | ||
627 | } | ||
628 | |||
629 | if ((regval32 & (1 << p->enable_bit)) == 0) | ||
630 | continue; | ||
631 | |||
632 | /* FIXME: This clock seems to be necessary but no-one | ||
633 | * has asked for its activation. */ | ||
634 | if (p == &tc2_ck // FIX: pm.c (SRAM), CCP, Camera | ||
635 | || p == &ck_dpll1out.clk // FIX: SoSSI, SSR | ||
636 | || p == &arm_gpio_ck // FIX: GPIO code for 1510 | ||
637 | ) { | ||
638 | printk(KERN_INFO "FIXME: Clock \"%s\" seems unused\n", | ||
639 | p->name); | ||
640 | continue; | ||
641 | } | ||
642 | |||
643 | printk(KERN_INFO "Disabling unused clock \"%s\"... ", p->name); | ||
644 | p->disable(p); | ||
645 | printk(" done\n"); | ||
646 | } | ||
647 | |||
648 | return 0; | ||
649 | } | ||
650 | late_initcall(omap1_late_clk_reset); | ||
651 | |||
652 | #else | ||
653 | #define omap1_early_clk_reset() {} | ||
654 | #endif | ||
655 | |||
656 | static struct clk_functions omap1_clk_functions = { | ||
657 | .clk_use = omap1_clk_use, | ||
658 | .clk_unuse = omap1_clk_unuse, | ||
659 | .clk_round_rate = omap1_clk_round_rate, | ||
660 | .clk_set_rate = omap1_clk_set_rate, | ||
661 | }; | ||
662 | |||
663 | int __init omap1_clk_init(void) | ||
664 | { | ||
665 | struct clk ** clkp; | ||
666 | const struct omap_clock_config *info; | ||
667 | int crystal_type = 0; /* Default 12 MHz */ | ||
668 | |||
669 | omap1_early_clk_reset(); | ||
670 | clk_init(&omap1_clk_functions); | ||
671 | |||
672 | /* By default all idlect1 clocks are allowed to idle */ | ||
673 | arm_idlect1_mask = ~0; | ||
674 | |||
675 | for (clkp = onchip_clks; clkp < onchip_clks+ARRAY_SIZE(onchip_clks); clkp++) { | ||
676 | if (((*clkp)->flags &CLOCK_IN_OMAP1510) && cpu_is_omap1510()) { | ||
677 | clk_register(*clkp); | ||
678 | continue; | ||
679 | } | ||
680 | |||
681 | if (((*clkp)->flags &CLOCK_IN_OMAP16XX) && cpu_is_omap16xx()) { | ||
682 | clk_register(*clkp); | ||
683 | continue; | ||
684 | } | ||
685 | |||
686 | if (((*clkp)->flags &CLOCK_IN_OMAP730) && cpu_is_omap730()) { | ||
687 | clk_register(*clkp); | ||
688 | continue; | ||
689 | } | ||
690 | } | ||
691 | |||
692 | info = omap_get_config(OMAP_TAG_CLOCK, struct omap_clock_config); | ||
693 | if (info != NULL) { | ||
694 | if (!cpu_is_omap1510()) | ||
695 | crystal_type = info->system_clock_type; | ||
696 | } | ||
697 | |||
698 | #if defined(CONFIG_ARCH_OMAP730) | ||
699 | ck_ref.rate = 13000000; | ||
700 | #elif defined(CONFIG_ARCH_OMAP16XX) | ||
701 | if (crystal_type == 2) | ||
702 | ck_ref.rate = 19200000; | ||
703 | #endif | ||
704 | |||
705 | printk("Clocks: ARM_SYSST: 0x%04x DPLL_CTL: 0x%04x ARM_CKCTL: 0x%04x\n", | ||
706 | omap_readw(ARM_SYSST), omap_readw(DPLL_CTL), | ||
707 | omap_readw(ARM_CKCTL)); | ||
708 | |||
709 | /* We want to be in syncronous scalable mode */ | ||
710 | omap_writew(0x1000, ARM_SYSST); | ||
711 | |||
712 | #ifdef CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER | ||
713 | /* Use values set by bootloader. Determine PLL rate and recalculate | ||
714 | * dependent clocks as if kernel had changed PLL or divisors. | ||
715 | */ | ||
716 | { | ||
717 | unsigned pll_ctl_val = omap_readw(DPLL_CTL); | ||
718 | |||
719 | ck_dpll1.rate = ck_ref.rate; /* Base xtal rate */ | ||
720 | if (pll_ctl_val & 0x10) { | ||
721 | /* PLL enabled, apply multiplier and divisor */ | ||
722 | if (pll_ctl_val & 0xf80) | ||
723 | ck_dpll1.rate *= (pll_ctl_val & 0xf80) >> 7; | ||
724 | ck_dpll1.rate /= ((pll_ctl_val & 0x60) >> 5) + 1; | ||
725 | } else { | ||
726 | /* PLL disabled, apply bypass divisor */ | ||
727 | switch (pll_ctl_val & 0xc) { | ||
728 | case 0: | ||
729 | break; | ||
730 | case 0x4: | ||
731 | ck_dpll1.rate /= 2; | ||
732 | break; | ||
733 | default: | ||
734 | ck_dpll1.rate /= 4; | ||
735 | break; | ||
736 | } | ||
737 | } | ||
738 | } | ||
739 | propagate_rate(&ck_dpll1); | ||
740 | #else | ||
741 | /* Find the highest supported frequency and enable it */ | ||
742 | if (omap1_select_table_rate(&virtual_ck_mpu, ~0)) { | ||
743 | printk(KERN_ERR "System frequencies not set. Check your config.\n"); | ||
744 | /* Guess sane values (60MHz) */ | ||
745 | omap_writew(0x2290, DPLL_CTL); | ||
746 | omap_writew(0x1005, ARM_CKCTL); | ||
747 | ck_dpll1.rate = 60000000; | ||
748 | propagate_rate(&ck_dpll1); | ||
749 | } | ||
750 | #endif | ||
751 | /* Cache rates for clocks connected to ck_ref (not dpll1) */ | ||
752 | propagate_rate(&ck_ref); | ||
753 | printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): " | ||
754 | "%ld.%01ld/%ld.%01ld/%ld.%01ld MHz\n", | ||
755 | ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10, | ||
756 | ck_dpll1.rate / 1000000, (ck_dpll1.rate / 100000) % 10, | ||
757 | arm_ck.rate / 1000000, (arm_ck.rate / 100000) % 10); | ||
758 | |||
759 | #ifdef CONFIG_MACH_OMAP_PERSEUS2 | ||
760 | /* Select slicer output as OMAP input clock */ | ||
761 | omap_writew(omap_readw(OMAP730_PCC_UPLD_CTRL) & ~0x1, OMAP730_PCC_UPLD_CTRL); | ||
762 | #endif | ||
763 | |||
764 | /* Turn off DSP and ARM_TIMXO. Make sure ARM_INTHCK is not divided */ | ||
765 | omap_writew(omap_readw(ARM_CKCTL) & 0x0fff, ARM_CKCTL); | ||
766 | |||
767 | /* Put DSP/MPUI into reset until needed */ | ||
768 | omap_writew(0, ARM_RSTCT1); | ||
769 | omap_writew(1, ARM_RSTCT2); | ||
770 | omap_writew(0x400, ARM_IDLECT1); | ||
771 | |||
772 | /* | ||
773 | * According to OMAP5910 Erratum SYS_DMA_1, bit DMACK_REQ (bit 8) | ||
774 | * of the ARM_IDLECT2 register must be set to zero. The power-on | ||
775 | * default value of this bit is one. | ||
776 | */ | ||
777 | omap_writew(0x0000, ARM_IDLECT2); /* Turn LCD clock off also */ | ||
778 | |||
779 | /* | ||
780 | * Only enable those clocks we will need, let the drivers | ||
781 | * enable other clocks as necessary | ||
782 | */ | ||
783 | clk_use(&armper_ck.clk); | ||
784 | clk_use(&armxor_ck.clk); | ||
785 | clk_use(&armtim_ck.clk); /* This should be done by timer code */ | ||
786 | |||
787 | if (cpu_is_omap1510()) | ||
788 | clk_enable(&arm_gpio_ck); | ||
789 | |||
790 | return 0; | ||
791 | } | ||
792 | |||
diff --git a/arch/arm/mach-omap1/clock.h b/arch/arm/mach-omap1/clock.h new file mode 100644 index 000000000000..f3bdfb50e01a --- /dev/null +++ b/arch/arm/mach-omap1/clock.h | |||
@@ -0,0 +1,768 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-omap1/clock.h | ||
3 | * | ||
4 | * Copyright (C) 2004 - 2005 Nokia corporation | ||
5 | * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> | ||
6 | * Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, Inc | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef __ARCH_ARM_MACH_OMAP1_CLOCK_H | ||
14 | #define __ARCH_ARM_MACH_OMAP1_CLOCK_H | ||
15 | |||
16 | static int omap1_clk_enable(struct clk * clk); | ||
17 | static void omap1_clk_disable(struct clk * clk); | ||
18 | static void omap1_ckctl_recalc(struct clk * clk); | ||
19 | static void omap1_watchdog_recalc(struct clk * clk); | ||
20 | static void omap1_ckctl_recalc_dsp_domain(struct clk * clk); | ||
21 | static int omap1_clk_enable_dsp_domain(struct clk * clk); | ||
22 | static int omap1_clk_set_rate_dsp_domain(struct clk * clk, unsigned long rate); | ||
23 | static void omap1_clk_disable_dsp_domain(struct clk * clk); | ||
24 | static int omap1_set_uart_rate(struct clk * clk, unsigned long rate); | ||
25 | static void omap1_uart_recalc(struct clk * clk); | ||
26 | static int omap1_clk_enable_uart_functional(struct clk * clk); | ||
27 | static void omap1_clk_disable_uart_functional(struct clk * clk); | ||
28 | static int omap1_set_ext_clk_rate(struct clk * clk, unsigned long rate); | ||
29 | static long omap1_round_ext_clk_rate(struct clk * clk, unsigned long rate); | ||
30 | static void omap1_init_ext_clk(struct clk * clk); | ||
31 | static int omap1_select_table_rate(struct clk * clk, unsigned long rate); | ||
32 | static long omap1_round_to_table_rate(struct clk * clk, unsigned long rate); | ||
33 | static int omap1_clk_use(struct clk *clk); | ||
34 | static void omap1_clk_unuse(struct clk *clk); | ||
35 | |||
36 | struct mpu_rate { | ||
37 | unsigned long rate; | ||
38 | unsigned long xtal; | ||
39 | unsigned long pll_rate; | ||
40 | __u16 ckctl_val; | ||
41 | __u16 dpllctl_val; | ||
42 | }; | ||
43 | |||
44 | struct uart_clk { | ||
45 | struct clk clk; | ||
46 | unsigned long sysc_addr; | ||
47 | }; | ||
48 | |||
49 | /* Provide a method for preventing idling some ARM IDLECT clocks */ | ||
50 | struct arm_idlect1_clk { | ||
51 | struct clk clk; | ||
52 | unsigned long no_idle_count; | ||
53 | __u8 idlect_shift; | ||
54 | }; | ||
55 | |||
56 | /* ARM_CKCTL bit shifts */ | ||
57 | #define CKCTL_PERDIV_OFFSET 0 | ||
58 | #define CKCTL_LCDDIV_OFFSET 2 | ||
59 | #define CKCTL_ARMDIV_OFFSET 4 | ||
60 | #define CKCTL_DSPDIV_OFFSET 6 | ||
61 | #define CKCTL_TCDIV_OFFSET 8 | ||
62 | #define CKCTL_DSPMMUDIV_OFFSET 10 | ||
63 | /*#define ARM_TIMXO 12*/ | ||
64 | #define EN_DSPCK 13 | ||
65 | /*#define ARM_INTHCK_SEL 14*/ /* Divide-by-2 for mpu inth_ck */ | ||
66 | /* DSP_CKCTL bit shifts */ | ||
67 | #define CKCTL_DSPPERDIV_OFFSET 0 | ||
68 | |||
69 | /* ARM_IDLECT2 bit shifts */ | ||
70 | #define EN_WDTCK 0 | ||
71 | #define EN_XORPCK 1 | ||
72 | #define EN_PERCK 2 | ||
73 | #define EN_LCDCK 3 | ||
74 | #define EN_LBCK 4 /* Not on 1610/1710 */ | ||
75 | /*#define EN_HSABCK 5*/ | ||
76 | #define EN_APICK 6 | ||
77 | #define EN_TIMCK 7 | ||
78 | #define DMACK_REQ 8 | ||
79 | #define EN_GPIOCK 9 /* Not on 1610/1710 */ | ||
80 | /*#define EN_LBFREECK 10*/ | ||
81 | #define EN_CKOUT_ARM 11 | ||
82 | |||
83 | /* ARM_IDLECT3 bit shifts */ | ||
84 | #define EN_OCPI_CK 0 | ||
85 | #define EN_TC1_CK 2 | ||
86 | #define EN_TC2_CK 4 | ||
87 | |||
88 | /* DSP_IDLECT2 bit shifts (0,1,2 are same as for ARM_IDLECT2) */ | ||
89 | #define EN_DSPTIMCK 5 | ||
90 | |||
91 | /* Various register defines for clock controls scattered around OMAP chip */ | ||
92 | #define USB_MCLK_EN_BIT 4 /* In ULPD_CLKC_CTRL */ | ||
93 | #define USB_HOST_HHC_UHOST_EN 9 /* In MOD_CONF_CTRL_0 */ | ||
94 | #define SWD_ULPD_PLL_CLK_REQ 1 /* In SWD_CLK_DIV_CTRL_SEL */ | ||
95 | #define COM_ULPD_PLL_CLK_REQ 1 /* In COM_CLK_DIV_CTRL_SEL */ | ||
96 | #define SWD_CLK_DIV_CTRL_SEL 0xfffe0874 | ||
97 | #define COM_CLK_DIV_CTRL_SEL 0xfffe0878 | ||
98 | #define SOFT_REQ_REG 0xfffe0834 | ||
99 | #define SOFT_REQ_REG2 0xfffe0880 | ||
100 | |||
101 | /*------------------------------------------------------------------------- | ||
102 | * Omap1 MPU rate table | ||
103 | *-------------------------------------------------------------------------*/ | ||
104 | static struct mpu_rate rate_table[] = { | ||
105 | /* MPU MHz, xtal MHz, dpll1 MHz, CKCTL, DPLL_CTL | ||
106 | * NOTE: Comment order here is different from bits in CKCTL value: | ||
107 | * armdiv, dspdiv, dspmmu, tcdiv, perdiv, lcddiv | ||
108 | */ | ||
109 | #if defined(CONFIG_OMAP_ARM_216MHZ) | ||
110 | { 216000000, 12000000, 216000000, 0x050d, 0x2910 }, /* 1/1/2/2/2/8 */ | ||
111 | #endif | ||
112 | #if defined(CONFIG_OMAP_ARM_195MHZ) | ||
113 | { 195000000, 13000000, 195000000, 0x050e, 0x2790 }, /* 1/1/2/2/4/8 */ | ||
114 | #endif | ||
115 | #if defined(CONFIG_OMAP_ARM_192MHZ) | ||
116 | { 192000000, 19200000, 192000000, 0x050f, 0x2510 }, /* 1/1/2/2/8/8 */ | ||
117 | { 192000000, 12000000, 192000000, 0x050f, 0x2810 }, /* 1/1/2/2/8/8 */ | ||
118 | { 96000000, 12000000, 192000000, 0x055f, 0x2810 }, /* 2/2/2/2/8/8 */ | ||
119 | { 48000000, 12000000, 192000000, 0x0baf, 0x2810 }, /* 4/4/4/8/8/8 */ | ||
120 | { 24000000, 12000000, 192000000, 0x0fff, 0x2810 }, /* 8/8/8/8/8/8 */ | ||
121 | #endif | ||
122 | #if defined(CONFIG_OMAP_ARM_182MHZ) | ||
123 | { 182000000, 13000000, 182000000, 0x050e, 0x2710 }, /* 1/1/2/2/4/8 */ | ||
124 | #endif | ||
125 | #if defined(CONFIG_OMAP_ARM_168MHZ) | ||
126 | { 168000000, 12000000, 168000000, 0x010f, 0x2710 }, /* 1/1/1/2/8/8 */ | ||
127 | #endif | ||
128 | #if defined(CONFIG_OMAP_ARM_150MHZ) | ||
129 | { 150000000, 12000000, 150000000, 0x010a, 0x2cb0 }, /* 1/1/1/2/4/4 */ | ||
130 | #endif | ||
131 | #if defined(CONFIG_OMAP_ARM_120MHZ) | ||
132 | { 120000000, 12000000, 120000000, 0x010a, 0x2510 }, /* 1/1/1/2/4/4 */ | ||
133 | #endif | ||
134 | #if defined(CONFIG_OMAP_ARM_96MHZ) | ||
135 | { 96000000, 12000000, 96000000, 0x0005, 0x2410 }, /* 1/1/1/1/2/2 */ | ||
136 | #endif | ||
137 | #if defined(CONFIG_OMAP_ARM_60MHZ) | ||
138 | { 60000000, 12000000, 60000000, 0x0005, 0x2290 }, /* 1/1/1/1/2/2 */ | ||
139 | #endif | ||
140 | #if defined(CONFIG_OMAP_ARM_30MHZ) | ||
141 | { 30000000, 12000000, 60000000, 0x0555, 0x2290 }, /* 2/2/2/2/2/2 */ | ||
142 | #endif | ||
143 | { 0, 0, 0, 0, 0 }, | ||
144 | }; | ||
145 | |||
146 | /*------------------------------------------------------------------------- | ||
147 | * Omap1 clocks | ||
148 | *-------------------------------------------------------------------------*/ | ||
149 | |||
150 | static struct clk ck_ref = { | ||
151 | .name = "ck_ref", | ||
152 | .rate = 12000000, | ||
153 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
154 | ALWAYS_ENABLED, | ||
155 | .enable = &omap1_clk_enable, | ||
156 | .disable = &omap1_clk_disable, | ||
157 | }; | ||
158 | |||
159 | static struct clk ck_dpll1 = { | ||
160 | .name = "ck_dpll1", | ||
161 | .parent = &ck_ref, | ||
162 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
163 | RATE_PROPAGATES | ALWAYS_ENABLED, | ||
164 | .enable = &omap1_clk_enable, | ||
165 | .disable = &omap1_clk_disable, | ||
166 | }; | ||
167 | |||
168 | static struct arm_idlect1_clk ck_dpll1out = { | ||
169 | .clk = { | ||
170 | .name = "ck_dpll1out", | ||
171 | .parent = &ck_dpll1, | ||
172 | .flags = CLOCK_IN_OMAP16XX | CLOCK_IDLE_CONTROL, | ||
173 | .enable_reg = (void __iomem *)ARM_IDLECT2, | ||
174 | .enable_bit = EN_CKOUT_ARM, | ||
175 | .recalc = &followparent_recalc, | ||
176 | .enable = &omap1_clk_enable, | ||
177 | .disable = &omap1_clk_disable, | ||
178 | }, | ||
179 | .idlect_shift = 12, | ||
180 | }; | ||
181 | |||
182 | static struct clk arm_ck = { | ||
183 | .name = "arm_ck", | ||
184 | .parent = &ck_dpll1, | ||
185 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
186 | RATE_CKCTL | RATE_PROPAGATES | ALWAYS_ENABLED, | ||
187 | .rate_offset = CKCTL_ARMDIV_OFFSET, | ||
188 | .recalc = &omap1_ckctl_recalc, | ||
189 | .enable = &omap1_clk_enable, | ||
190 | .disable = &omap1_clk_disable, | ||
191 | }; | ||
192 | |||
193 | static struct arm_idlect1_clk armper_ck = { | ||
194 | .clk = { | ||
195 | .name = "armper_ck", | ||
196 | .parent = &ck_dpll1, | ||
197 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
198 | RATE_CKCTL | CLOCK_IDLE_CONTROL, | ||
199 | .enable_reg = (void __iomem *)ARM_IDLECT2, | ||
200 | .enable_bit = EN_PERCK, | ||
201 | .rate_offset = CKCTL_PERDIV_OFFSET, | ||
202 | .recalc = &omap1_ckctl_recalc, | ||
203 | .enable = &omap1_clk_enable, | ||
204 | .disable = &omap1_clk_disable, | ||
205 | }, | ||
206 | .idlect_shift = 2, | ||
207 | }; | ||
208 | |||
209 | static struct clk arm_gpio_ck = { | ||
210 | .name = "arm_gpio_ck", | ||
211 | .parent = &ck_dpll1, | ||
212 | .flags = CLOCK_IN_OMAP1510, | ||
213 | .enable_reg = (void __iomem *)ARM_IDLECT2, | ||
214 | .enable_bit = EN_GPIOCK, | ||
215 | .recalc = &followparent_recalc, | ||
216 | .enable = &omap1_clk_enable, | ||
217 | .disable = &omap1_clk_disable, | ||
218 | }; | ||
219 | |||
220 | static struct arm_idlect1_clk armxor_ck = { | ||
221 | .clk = { | ||
222 | .name = "armxor_ck", | ||
223 | .parent = &ck_ref, | ||
224 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
225 | CLOCK_IDLE_CONTROL, | ||
226 | .enable_reg = (void __iomem *)ARM_IDLECT2, | ||
227 | .enable_bit = EN_XORPCK, | ||
228 | .recalc = &followparent_recalc, | ||
229 | .enable = &omap1_clk_enable, | ||
230 | .disable = &omap1_clk_disable, | ||
231 | }, | ||
232 | .idlect_shift = 1, | ||
233 | }; | ||
234 | |||
235 | static struct arm_idlect1_clk armtim_ck = { | ||
236 | .clk = { | ||
237 | .name = "armtim_ck", | ||
238 | .parent = &ck_ref, | ||
239 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
240 | CLOCK_IDLE_CONTROL, | ||
241 | .enable_reg = (void __iomem *)ARM_IDLECT2, | ||
242 | .enable_bit = EN_TIMCK, | ||
243 | .recalc = &followparent_recalc, | ||
244 | .enable = &omap1_clk_enable, | ||
245 | .disable = &omap1_clk_disable, | ||
246 | }, | ||
247 | .idlect_shift = 9, | ||
248 | }; | ||
249 | |||
250 | static struct arm_idlect1_clk armwdt_ck = { | ||
251 | .clk = { | ||
252 | .name = "armwdt_ck", | ||
253 | .parent = &ck_ref, | ||
254 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
255 | CLOCK_IDLE_CONTROL, | ||
256 | .enable_reg = (void __iomem *)ARM_IDLECT2, | ||
257 | .enable_bit = EN_WDTCK, | ||
258 | .recalc = &omap1_watchdog_recalc, | ||
259 | .enable = &omap1_clk_enable, | ||
260 | .disable = &omap1_clk_disable, | ||
261 | }, | ||
262 | .idlect_shift = 0, | ||
263 | }; | ||
264 | |||
265 | static struct clk arminth_ck16xx = { | ||
266 | .name = "arminth_ck", | ||
267 | .parent = &arm_ck, | ||
268 | .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, | ||
269 | .recalc = &followparent_recalc, | ||
270 | /* Note: On 16xx the frequency can be divided by 2 by programming | ||
271 | * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1 | ||
272 | * | ||
273 | * 1510 version is in TC clocks. | ||
274 | */ | ||
275 | .enable = &omap1_clk_enable, | ||
276 | .disable = &omap1_clk_disable, | ||
277 | }; | ||
278 | |||
279 | static struct clk dsp_ck = { | ||
280 | .name = "dsp_ck", | ||
281 | .parent = &ck_dpll1, | ||
282 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
283 | RATE_CKCTL, | ||
284 | .enable_reg = (void __iomem *)ARM_CKCTL, | ||
285 | .enable_bit = EN_DSPCK, | ||
286 | .rate_offset = CKCTL_DSPDIV_OFFSET, | ||
287 | .recalc = &omap1_ckctl_recalc, | ||
288 | .enable = &omap1_clk_enable, | ||
289 | .disable = &omap1_clk_disable, | ||
290 | }; | ||
291 | |||
292 | static struct clk dspmmu_ck = { | ||
293 | .name = "dspmmu_ck", | ||
294 | .parent = &ck_dpll1, | ||
295 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
296 | RATE_CKCTL | ALWAYS_ENABLED, | ||
297 | .rate_offset = CKCTL_DSPMMUDIV_OFFSET, | ||
298 | .recalc = &omap1_ckctl_recalc, | ||
299 | .enable = &omap1_clk_enable, | ||
300 | .disable = &omap1_clk_disable, | ||
301 | }; | ||
302 | |||
303 | static struct clk dspper_ck = { | ||
304 | .name = "dspper_ck", | ||
305 | .parent = &ck_dpll1, | ||
306 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
307 | RATE_CKCTL | VIRTUAL_IO_ADDRESS, | ||
308 | .enable_reg = (void __iomem *)DSP_IDLECT2, | ||
309 | .enable_bit = EN_PERCK, | ||
310 | .rate_offset = CKCTL_PERDIV_OFFSET, | ||
311 | .recalc = &omap1_ckctl_recalc_dsp_domain, | ||
312 | .set_rate = &omap1_clk_set_rate_dsp_domain, | ||
313 | .enable = &omap1_clk_enable_dsp_domain, | ||
314 | .disable = &omap1_clk_disable_dsp_domain, | ||
315 | }; | ||
316 | |||
317 | static struct clk dspxor_ck = { | ||
318 | .name = "dspxor_ck", | ||
319 | .parent = &ck_ref, | ||
320 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
321 | VIRTUAL_IO_ADDRESS, | ||
322 | .enable_reg = (void __iomem *)DSP_IDLECT2, | ||
323 | .enable_bit = EN_XORPCK, | ||
324 | .recalc = &followparent_recalc, | ||
325 | .enable = &omap1_clk_enable_dsp_domain, | ||
326 | .disable = &omap1_clk_disable_dsp_domain, | ||
327 | }; | ||
328 | |||
329 | static struct clk dsptim_ck = { | ||
330 | .name = "dsptim_ck", | ||
331 | .parent = &ck_ref, | ||
332 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
333 | VIRTUAL_IO_ADDRESS, | ||
334 | .enable_reg = (void __iomem *)DSP_IDLECT2, | ||
335 | .enable_bit = EN_DSPTIMCK, | ||
336 | .recalc = &followparent_recalc, | ||
337 | .enable = &omap1_clk_enable_dsp_domain, | ||
338 | .disable = &omap1_clk_disable_dsp_domain, | ||
339 | }; | ||
340 | |||
341 | /* Tie ARM_IDLECT1:IDLIF_ARM to this logical clock structure */ | ||
342 | static struct arm_idlect1_clk tc_ck = { | ||
343 | .clk = { | ||
344 | .name = "tc_ck", | ||
345 | .parent = &ck_dpll1, | ||
346 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
347 | CLOCK_IN_OMAP730 | RATE_CKCTL | | ||
348 | RATE_PROPAGATES | ALWAYS_ENABLED | | ||
349 | CLOCK_IDLE_CONTROL, | ||
350 | .rate_offset = CKCTL_TCDIV_OFFSET, | ||
351 | .recalc = &omap1_ckctl_recalc, | ||
352 | .enable = &omap1_clk_enable, | ||
353 | .disable = &omap1_clk_disable, | ||
354 | }, | ||
355 | .idlect_shift = 6, | ||
356 | }; | ||
357 | |||
358 | static struct clk arminth_ck1510 = { | ||
359 | .name = "arminth_ck", | ||
360 | .parent = &tc_ck.clk, | ||
361 | .flags = CLOCK_IN_OMAP1510 | ALWAYS_ENABLED, | ||
362 | .recalc = &followparent_recalc, | ||
363 | /* Note: On 1510 the frequency follows TC_CK | ||
364 | * | ||
365 | * 16xx version is in MPU clocks. | ||
366 | */ | ||
367 | .enable = &omap1_clk_enable, | ||
368 | .disable = &omap1_clk_disable, | ||
369 | }; | ||
370 | |||
371 | static struct clk tipb_ck = { | ||
372 | /* No-idle controlled by "tc_ck" */ | ||
373 | .name = "tibp_ck", | ||
374 | .parent = &tc_ck.clk, | ||
375 | .flags = CLOCK_IN_OMAP1510 | ALWAYS_ENABLED, | ||
376 | .recalc = &followparent_recalc, | ||
377 | .enable = &omap1_clk_enable, | ||
378 | .disable = &omap1_clk_disable, | ||
379 | }; | ||
380 | |||
381 | static struct clk l3_ocpi_ck = { | ||
382 | /* No-idle controlled by "tc_ck" */ | ||
383 | .name = "l3_ocpi_ck", | ||
384 | .parent = &tc_ck.clk, | ||
385 | .flags = CLOCK_IN_OMAP16XX, | ||
386 | .enable_reg = (void __iomem *)ARM_IDLECT3, | ||
387 | .enable_bit = EN_OCPI_CK, | ||
388 | .recalc = &followparent_recalc, | ||
389 | .enable = &omap1_clk_enable, | ||
390 | .disable = &omap1_clk_disable, | ||
391 | }; | ||
392 | |||
393 | static struct clk tc1_ck = { | ||
394 | .name = "tc1_ck", | ||
395 | .parent = &tc_ck.clk, | ||
396 | .flags = CLOCK_IN_OMAP16XX, | ||
397 | .enable_reg = (void __iomem *)ARM_IDLECT3, | ||
398 | .enable_bit = EN_TC1_CK, | ||
399 | .recalc = &followparent_recalc, | ||
400 | .enable = &omap1_clk_enable, | ||
401 | .disable = &omap1_clk_disable, | ||
402 | }; | ||
403 | |||
404 | static struct clk tc2_ck = { | ||
405 | .name = "tc2_ck", | ||
406 | .parent = &tc_ck.clk, | ||
407 | .flags = CLOCK_IN_OMAP16XX, | ||
408 | .enable_reg = (void __iomem *)ARM_IDLECT3, | ||
409 | .enable_bit = EN_TC2_CK, | ||
410 | .recalc = &followparent_recalc, | ||
411 | .enable = &omap1_clk_enable, | ||
412 | .disable = &omap1_clk_disable, | ||
413 | }; | ||
414 | |||
415 | static struct clk dma_ck = { | ||
416 | /* No-idle controlled by "tc_ck" */ | ||
417 | .name = "dma_ck", | ||
418 | .parent = &tc_ck.clk, | ||
419 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
420 | ALWAYS_ENABLED, | ||
421 | .recalc = &followparent_recalc, | ||
422 | .enable = &omap1_clk_enable, | ||
423 | .disable = &omap1_clk_disable, | ||
424 | }; | ||
425 | |||
426 | static struct clk dma_lcdfree_ck = { | ||
427 | .name = "dma_lcdfree_ck", | ||
428 | .parent = &tc_ck.clk, | ||
429 | .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, | ||
430 | .recalc = &followparent_recalc, | ||
431 | .enable = &omap1_clk_enable, | ||
432 | .disable = &omap1_clk_disable, | ||
433 | }; | ||
434 | |||
435 | static struct arm_idlect1_clk api_ck = { | ||
436 | .clk = { | ||
437 | .name = "api_ck", | ||
438 | .parent = &tc_ck.clk, | ||
439 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
440 | CLOCK_IDLE_CONTROL, | ||
441 | .enable_reg = (void __iomem *)ARM_IDLECT2, | ||
442 | .enable_bit = EN_APICK, | ||
443 | .recalc = &followparent_recalc, | ||
444 | .enable = &omap1_clk_enable, | ||
445 | .disable = &omap1_clk_disable, | ||
446 | }, | ||
447 | .idlect_shift = 8, | ||
448 | }; | ||
449 | |||
450 | static struct arm_idlect1_clk lb_ck = { | ||
451 | .clk = { | ||
452 | .name = "lb_ck", | ||
453 | .parent = &tc_ck.clk, | ||
454 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IDLE_CONTROL, | ||
455 | .enable_reg = (void __iomem *)ARM_IDLECT2, | ||
456 | .enable_bit = EN_LBCK, | ||
457 | .recalc = &followparent_recalc, | ||
458 | .enable = &omap1_clk_enable, | ||
459 | .disable = &omap1_clk_disable, | ||
460 | }, | ||
461 | .idlect_shift = 4, | ||
462 | }; | ||
463 | |||
464 | static struct clk rhea1_ck = { | ||
465 | .name = "rhea1_ck", | ||
466 | .parent = &tc_ck.clk, | ||
467 | .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, | ||
468 | .recalc = &followparent_recalc, | ||
469 | .enable = &omap1_clk_enable, | ||
470 | .disable = &omap1_clk_disable, | ||
471 | }; | ||
472 | |||
473 | static struct clk rhea2_ck = { | ||
474 | .name = "rhea2_ck", | ||
475 | .parent = &tc_ck.clk, | ||
476 | .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, | ||
477 | .recalc = &followparent_recalc, | ||
478 | .enable = &omap1_clk_enable, | ||
479 | .disable = &omap1_clk_disable, | ||
480 | }; | ||
481 | |||
482 | static struct clk lcd_ck_16xx = { | ||
483 | .name = "lcd_ck", | ||
484 | .parent = &ck_dpll1, | ||
485 | .flags = CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730 | RATE_CKCTL, | ||
486 | .enable_reg = (void __iomem *)ARM_IDLECT2, | ||
487 | .enable_bit = EN_LCDCK, | ||
488 | .rate_offset = CKCTL_LCDDIV_OFFSET, | ||
489 | .recalc = &omap1_ckctl_recalc, | ||
490 | .enable = &omap1_clk_enable, | ||
491 | .disable = &omap1_clk_disable, | ||
492 | }; | ||
493 | |||
494 | static struct arm_idlect1_clk lcd_ck_1510 = { | ||
495 | .clk = { | ||
496 | .name = "lcd_ck", | ||
497 | .parent = &ck_dpll1, | ||
498 | .flags = CLOCK_IN_OMAP1510 | RATE_CKCTL | | ||
499 | CLOCK_IDLE_CONTROL, | ||
500 | .enable_reg = (void __iomem *)ARM_IDLECT2, | ||
501 | .enable_bit = EN_LCDCK, | ||
502 | .rate_offset = CKCTL_LCDDIV_OFFSET, | ||
503 | .recalc = &omap1_ckctl_recalc, | ||
504 | .enable = &omap1_clk_enable, | ||
505 | .disable = &omap1_clk_disable, | ||
506 | }, | ||
507 | .idlect_shift = 3, | ||
508 | }; | ||
509 | |||
510 | static struct clk uart1_1510 = { | ||
511 | .name = "uart1_ck", | ||
512 | /* Direct from ULPD, no real parent */ | ||
513 | .parent = &armper_ck.clk, | ||
514 | .rate = 12000000, | ||
515 | .flags = CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | | ||
516 | ALWAYS_ENABLED | CLOCK_NO_IDLE_PARENT, | ||
517 | .enable_reg = (void __iomem *)MOD_CONF_CTRL_0, | ||
518 | .enable_bit = 29, /* Chooses between 12MHz and 48MHz */ | ||
519 | .set_rate = &omap1_set_uart_rate, | ||
520 | .recalc = &omap1_uart_recalc, | ||
521 | .enable = &omap1_clk_enable, | ||
522 | .disable = &omap1_clk_disable, | ||
523 | }; | ||
524 | |||
525 | static struct uart_clk uart1_16xx = { | ||
526 | .clk = { | ||
527 | .name = "uart1_ck", | ||
528 | /* Direct from ULPD, no real parent */ | ||
529 | .parent = &armper_ck.clk, | ||
530 | .rate = 48000000, | ||
531 | .flags = CLOCK_IN_OMAP16XX | RATE_FIXED | | ||
532 | ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT, | ||
533 | .enable_reg = (void __iomem *)MOD_CONF_CTRL_0, | ||
534 | .enable_bit = 29, | ||
535 | .enable = &omap1_clk_enable_uart_functional, | ||
536 | .disable = &omap1_clk_disable_uart_functional, | ||
537 | }, | ||
538 | .sysc_addr = 0xfffb0054, | ||
539 | }; | ||
540 | |||
541 | static struct clk uart2_ck = { | ||
542 | .name = "uart2_ck", | ||
543 | /* Direct from ULPD, no real parent */ | ||
544 | .parent = &armper_ck.clk, | ||
545 | .rate = 12000000, | ||
546 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
547 | ENABLE_REG_32BIT | ALWAYS_ENABLED | | ||
548 | CLOCK_NO_IDLE_PARENT, | ||
549 | .enable_reg = (void __iomem *)MOD_CONF_CTRL_0, | ||
550 | .enable_bit = 30, /* Chooses between 12MHz and 48MHz */ | ||
551 | .set_rate = &omap1_set_uart_rate, | ||
552 | .recalc = &omap1_uart_recalc, | ||
553 | .enable = &omap1_clk_enable, | ||
554 | .disable = &omap1_clk_disable, | ||
555 | }; | ||
556 | |||
557 | static struct clk uart3_1510 = { | ||
558 | .name = "uart3_ck", | ||
559 | /* Direct from ULPD, no real parent */ | ||
560 | .parent = &armper_ck.clk, | ||
561 | .rate = 12000000, | ||
562 | .flags = CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | | ||
563 | ALWAYS_ENABLED | CLOCK_NO_IDLE_PARENT, | ||
564 | .enable_reg = (void __iomem *)MOD_CONF_CTRL_0, | ||
565 | .enable_bit = 31, /* Chooses between 12MHz and 48MHz */ | ||
566 | .set_rate = &omap1_set_uart_rate, | ||
567 | .recalc = &omap1_uart_recalc, | ||
568 | .enable = &omap1_clk_enable, | ||
569 | .disable = &omap1_clk_disable, | ||
570 | }; | ||
571 | |||
572 | static struct uart_clk uart3_16xx = { | ||
573 | .clk = { | ||
574 | .name = "uart3_ck", | ||
575 | /* Direct from ULPD, no real parent */ | ||
576 | .parent = &armper_ck.clk, | ||
577 | .rate = 48000000, | ||
578 | .flags = CLOCK_IN_OMAP16XX | RATE_FIXED | | ||
579 | ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT, | ||
580 | .enable_reg = (void __iomem *)MOD_CONF_CTRL_0, | ||
581 | .enable_bit = 31, | ||
582 | .enable = &omap1_clk_enable_uart_functional, | ||
583 | .disable = &omap1_clk_disable_uart_functional, | ||
584 | }, | ||
585 | .sysc_addr = 0xfffb9854, | ||
586 | }; | ||
587 | |||
588 | static struct clk usb_clko = { /* 6 MHz output on W4_USB_CLKO */ | ||
589 | .name = "usb_clko", | ||
590 | /* Direct from ULPD, no parent */ | ||
591 | .rate = 6000000, | ||
592 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
593 | RATE_FIXED | ENABLE_REG_32BIT, | ||
594 | .enable_reg = (void __iomem *)ULPD_CLOCK_CTRL, | ||
595 | .enable_bit = USB_MCLK_EN_BIT, | ||
596 | .enable = &omap1_clk_enable, | ||
597 | .disable = &omap1_clk_disable, | ||
598 | }; | ||
599 | |||
600 | static struct clk usb_hhc_ck1510 = { | ||
601 | .name = "usb_hhc_ck", | ||
602 | /* Direct from ULPD, no parent */ | ||
603 | .rate = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */ | ||
604 | .flags = CLOCK_IN_OMAP1510 | | ||
605 | RATE_FIXED | ENABLE_REG_32BIT, | ||
606 | .enable_reg = (void __iomem *)MOD_CONF_CTRL_0, | ||
607 | .enable_bit = USB_HOST_HHC_UHOST_EN, | ||
608 | .enable = &omap1_clk_enable, | ||
609 | .disable = &omap1_clk_disable, | ||
610 | }; | ||
611 | |||
612 | static struct clk usb_hhc_ck16xx = { | ||
613 | .name = "usb_hhc_ck", | ||
614 | /* Direct from ULPD, no parent */ | ||
615 | .rate = 48000000, | ||
616 | /* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */ | ||
617 | .flags = CLOCK_IN_OMAP16XX | | ||
618 | RATE_FIXED | ENABLE_REG_32BIT, | ||
619 | .enable_reg = (void __iomem *)OTG_BASE + 0x08 /* OTG_SYSCON_2 */, | ||
620 | .enable_bit = 8 /* UHOST_EN */, | ||
621 | .enable = &omap1_clk_enable, | ||
622 | .disable = &omap1_clk_disable, | ||
623 | }; | ||
624 | |||
625 | static struct clk usb_dc_ck = { | ||
626 | .name = "usb_dc_ck", | ||
627 | /* Direct from ULPD, no parent */ | ||
628 | .rate = 48000000, | ||
629 | .flags = CLOCK_IN_OMAP16XX | RATE_FIXED, | ||
630 | .enable_reg = (void __iomem *)SOFT_REQ_REG, | ||
631 | .enable_bit = 4, | ||
632 | .enable = &omap1_clk_enable, | ||
633 | .disable = &omap1_clk_disable, | ||
634 | }; | ||
635 | |||
636 | static struct clk mclk_1510 = { | ||
637 | .name = "mclk", | ||
638 | /* Direct from ULPD, no parent. May be enabled by ext hardware. */ | ||
639 | .rate = 12000000, | ||
640 | .flags = CLOCK_IN_OMAP1510 | RATE_FIXED, | ||
641 | .enable = &omap1_clk_enable, | ||
642 | .disable = &omap1_clk_disable, | ||
643 | }; | ||
644 | |||
645 | static struct clk mclk_16xx = { | ||
646 | .name = "mclk", | ||
647 | /* Direct from ULPD, no parent. May be enabled by ext hardware. */ | ||
648 | .flags = CLOCK_IN_OMAP16XX, | ||
649 | .enable_reg = (void __iomem *)COM_CLK_DIV_CTRL_SEL, | ||
650 | .enable_bit = COM_ULPD_PLL_CLK_REQ, | ||
651 | .set_rate = &omap1_set_ext_clk_rate, | ||
652 | .round_rate = &omap1_round_ext_clk_rate, | ||
653 | .init = &omap1_init_ext_clk, | ||
654 | .enable = &omap1_clk_enable, | ||
655 | .disable = &omap1_clk_disable, | ||
656 | }; | ||
657 | |||
658 | static struct clk bclk_1510 = { | ||
659 | .name = "bclk", | ||
660 | /* Direct from ULPD, no parent. May be enabled by ext hardware. */ | ||
661 | .rate = 12000000, | ||
662 | .flags = CLOCK_IN_OMAP1510 | RATE_FIXED, | ||
663 | .enable = &omap1_clk_enable, | ||
664 | .disable = &omap1_clk_disable, | ||
665 | }; | ||
666 | |||
667 | static struct clk bclk_16xx = { | ||
668 | .name = "bclk", | ||
669 | /* Direct from ULPD, no parent. May be enabled by ext hardware. */ | ||
670 | .flags = CLOCK_IN_OMAP16XX, | ||
671 | .enable_reg = (void __iomem *)SWD_CLK_DIV_CTRL_SEL, | ||
672 | .enable_bit = SWD_ULPD_PLL_CLK_REQ, | ||
673 | .set_rate = &omap1_set_ext_clk_rate, | ||
674 | .round_rate = &omap1_round_ext_clk_rate, | ||
675 | .init = &omap1_init_ext_clk, | ||
676 | .enable = &omap1_clk_enable, | ||
677 | .disable = &omap1_clk_disable, | ||
678 | }; | ||
679 | |||
680 | static struct clk mmc1_ck = { | ||
681 | .name = "mmc1_ck", | ||
682 | /* Functional clock is direct from ULPD, interface clock is ARMPER */ | ||
683 | .parent = &armper_ck.clk, | ||
684 | .rate = 48000000, | ||
685 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
686 | RATE_FIXED | ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT, | ||
687 | .enable_reg = (void __iomem *)MOD_CONF_CTRL_0, | ||
688 | .enable_bit = 23, | ||
689 | .enable = &omap1_clk_enable, | ||
690 | .disable = &omap1_clk_disable, | ||
691 | }; | ||
692 | |||
693 | static struct clk mmc2_ck = { | ||
694 | .name = "mmc2_ck", | ||
695 | /* Functional clock is direct from ULPD, interface clock is ARMPER */ | ||
696 | .parent = &armper_ck.clk, | ||
697 | .rate = 48000000, | ||
698 | .flags = CLOCK_IN_OMAP16XX | | ||
699 | RATE_FIXED | ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT, | ||
700 | .enable_reg = (void __iomem *)MOD_CONF_CTRL_0, | ||
701 | .enable_bit = 20, | ||
702 | .enable = &omap1_clk_enable, | ||
703 | .disable = &omap1_clk_disable, | ||
704 | }; | ||
705 | |||
706 | static struct clk virtual_ck_mpu = { | ||
707 | .name = "mpu", | ||
708 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
709 | VIRTUAL_CLOCK | ALWAYS_ENABLED, | ||
710 | .parent = &arm_ck, /* Is smarter alias for */ | ||
711 | .recalc = &followparent_recalc, | ||
712 | .set_rate = &omap1_select_table_rate, | ||
713 | .round_rate = &omap1_round_to_table_rate, | ||
714 | .enable = &omap1_clk_enable, | ||
715 | .disable = &omap1_clk_disable, | ||
716 | }; | ||
717 | |||
718 | static struct clk * onchip_clks[] = { | ||
719 | /* non-ULPD clocks */ | ||
720 | &ck_ref, | ||
721 | &ck_dpll1, | ||
722 | /* CK_GEN1 clocks */ | ||
723 | &ck_dpll1out.clk, | ||
724 | &arm_ck, | ||
725 | &armper_ck.clk, | ||
726 | &arm_gpio_ck, | ||
727 | &armxor_ck.clk, | ||
728 | &armtim_ck.clk, | ||
729 | &armwdt_ck.clk, | ||
730 | &arminth_ck1510, &arminth_ck16xx, | ||
731 | /* CK_GEN2 clocks */ | ||
732 | &dsp_ck, | ||
733 | &dspmmu_ck, | ||
734 | &dspper_ck, | ||
735 | &dspxor_ck, | ||
736 | &dsptim_ck, | ||
737 | /* CK_GEN3 clocks */ | ||
738 | &tc_ck.clk, | ||
739 | &tipb_ck, | ||
740 | &l3_ocpi_ck, | ||
741 | &tc1_ck, | ||
742 | &tc2_ck, | ||
743 | &dma_ck, | ||
744 | &dma_lcdfree_ck, | ||
745 | &api_ck.clk, | ||
746 | &lb_ck.clk, | ||
747 | &rhea1_ck, | ||
748 | &rhea2_ck, | ||
749 | &lcd_ck_16xx, | ||
750 | &lcd_ck_1510.clk, | ||
751 | /* ULPD clocks */ | ||
752 | &uart1_1510, | ||
753 | &uart1_16xx.clk, | ||
754 | &uart2_ck, | ||
755 | &uart3_1510, | ||
756 | &uart3_16xx.clk, | ||
757 | &usb_clko, | ||
758 | &usb_hhc_ck1510, &usb_hhc_ck16xx, | ||
759 | &usb_dc_ck, | ||
760 | &mclk_1510, &mclk_16xx, | ||
761 | &bclk_1510, &bclk_16xx, | ||
762 | &mmc1_ck, | ||
763 | &mmc2_ck, | ||
764 | /* Virtual clocks */ | ||
765 | &virtual_ck_mpu, | ||
766 | }; | ||
767 | |||
768 | #endif | ||
diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c index 3c5d901efeaa..ecbc47514adc 100644 --- a/arch/arm/mach-omap1/devices.c +++ b/arch/arm/mach-omap1/devices.c | |||
@@ -25,56 +25,7 @@ | |||
25 | #include <asm/arch/mux.h> | 25 | #include <asm/arch/mux.h> |
26 | #include <asm/arch/gpio.h> | 26 | #include <asm/arch/gpio.h> |
27 | 27 | ||
28 | 28 | extern void omap_nop_release(struct device *dev); | |
29 | static void omap_nop_release(struct device *dev) | ||
30 | { | ||
31 | /* Nothing */ | ||
32 | } | ||
33 | |||
34 | /*-------------------------------------------------------------------------*/ | ||
35 | |||
36 | #if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE) | ||
37 | |||
38 | #define OMAP_I2C_BASE 0xfffb3800 | ||
39 | |||
40 | static struct resource i2c_resources[] = { | ||
41 | { | ||
42 | .start = OMAP_I2C_BASE, | ||
43 | .end = OMAP_I2C_BASE + 0x3f, | ||
44 | .flags = IORESOURCE_MEM, | ||
45 | }, | ||
46 | { | ||
47 | .start = INT_I2C, | ||
48 | .flags = IORESOURCE_IRQ, | ||
49 | }, | ||
50 | }; | ||
51 | |||
52 | /* DMA not used; works around erratum writing to non-empty i2c fifo */ | ||
53 | |||
54 | static struct platform_device omap_i2c_device = { | ||
55 | .name = "i2c_omap", | ||
56 | .id = -1, | ||
57 | .dev = { | ||
58 | .release = omap_nop_release, | ||
59 | }, | ||
60 | .num_resources = ARRAY_SIZE(i2c_resources), | ||
61 | .resource = i2c_resources, | ||
62 | }; | ||
63 | |||
64 | static void omap_init_i2c(void) | ||
65 | { | ||
66 | /* FIXME define and use a boot tag, in case of boards that | ||
67 | * either don't wire up I2C, or chips that mux it differently... | ||
68 | * it can include clocking and address info, maybe more. | ||
69 | */ | ||
70 | omap_cfg_reg(I2C_SCL); | ||
71 | omap_cfg_reg(I2C_SDA); | ||
72 | |||
73 | (void) platform_device_register(&omap_i2c_device); | ||
74 | } | ||
75 | #else | ||
76 | static inline void omap_init_i2c(void) {} | ||
77 | #endif | ||
78 | 29 | ||
79 | /*-------------------------------------------------------------------------*/ | 30 | /*-------------------------------------------------------------------------*/ |
80 | 31 | ||
@@ -110,137 +61,6 @@ static inline void omap_init_irda(void) {} | |||
110 | 61 | ||
111 | /*-------------------------------------------------------------------------*/ | 62 | /*-------------------------------------------------------------------------*/ |
112 | 63 | ||
113 | #if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) | ||
114 | |||
115 | #define OMAP_MMC1_BASE 0xfffb7800 | ||
116 | #define OMAP_MMC2_BASE 0xfffb7c00 /* omap16xx only */ | ||
117 | |||
118 | static struct omap_mmc_conf mmc1_conf; | ||
119 | |||
120 | static u64 mmc1_dmamask = 0xffffffff; | ||
121 | |||
122 | static struct resource mmc1_resources[] = { | ||
123 | { | ||
124 | .start = IO_ADDRESS(OMAP_MMC1_BASE), | ||
125 | .end = IO_ADDRESS(OMAP_MMC1_BASE) + 0x7f, | ||
126 | .flags = IORESOURCE_MEM, | ||
127 | }, | ||
128 | { | ||
129 | .start = INT_MMC, | ||
130 | .flags = IORESOURCE_IRQ, | ||
131 | }, | ||
132 | }; | ||
133 | |||
134 | static struct platform_device mmc_omap_device1 = { | ||
135 | .name = "mmci-omap", | ||
136 | .id = 1, | ||
137 | .dev = { | ||
138 | .release = omap_nop_release, | ||
139 | .dma_mask = &mmc1_dmamask, | ||
140 | .platform_data = &mmc1_conf, | ||
141 | }, | ||
142 | .num_resources = ARRAY_SIZE(mmc1_resources), | ||
143 | .resource = mmc1_resources, | ||
144 | }; | ||
145 | |||
146 | #ifdef CONFIG_ARCH_OMAP16XX | ||
147 | |||
148 | static struct omap_mmc_conf mmc2_conf; | ||
149 | |||
150 | static u64 mmc2_dmamask = 0xffffffff; | ||
151 | |||
152 | static struct resource mmc2_resources[] = { | ||
153 | { | ||
154 | .start = IO_ADDRESS(OMAP_MMC2_BASE), | ||
155 | .end = IO_ADDRESS(OMAP_MMC2_BASE) + 0x7f, | ||
156 | .flags = IORESOURCE_MEM, | ||
157 | }, | ||
158 | { | ||
159 | .start = INT_1610_MMC2, | ||
160 | .flags = IORESOURCE_IRQ, | ||
161 | }, | ||
162 | }; | ||
163 | |||
164 | static struct platform_device mmc_omap_device2 = { | ||
165 | .name = "mmci-omap", | ||
166 | .id = 2, | ||
167 | .dev = { | ||
168 | .release = omap_nop_release, | ||
169 | .dma_mask = &mmc2_dmamask, | ||
170 | .platform_data = &mmc2_conf, | ||
171 | }, | ||
172 | .num_resources = ARRAY_SIZE(mmc2_resources), | ||
173 | .resource = mmc2_resources, | ||
174 | }; | ||
175 | #endif | ||
176 | |||
177 | static void __init omap_init_mmc(void) | ||
178 | { | ||
179 | const struct omap_mmc_config *mmc_conf; | ||
180 | const struct omap_mmc_conf *mmc; | ||
181 | |||
182 | /* NOTE: assumes MMC was never (wrongly) enabled */ | ||
183 | mmc_conf = omap_get_config(OMAP_TAG_MMC, struct omap_mmc_config); | ||
184 | if (!mmc_conf) | ||
185 | return; | ||
186 | |||
187 | /* block 1 is always available and has just one pinout option */ | ||
188 | mmc = &mmc_conf->mmc[0]; | ||
189 | if (mmc->enabled) { | ||
190 | omap_cfg_reg(MMC_CMD); | ||
191 | omap_cfg_reg(MMC_CLK); | ||
192 | omap_cfg_reg(MMC_DAT0); | ||
193 | if (cpu_is_omap1710()) { | ||
194 | omap_cfg_reg(M15_1710_MMC_CLKI); | ||
195 | omap_cfg_reg(P19_1710_MMC_CMDDIR); | ||
196 | omap_cfg_reg(P20_1710_MMC_DATDIR0); | ||
197 | } | ||
198 | if (mmc->wire4) { | ||
199 | omap_cfg_reg(MMC_DAT1); | ||
200 | /* NOTE: DAT2 can be on W10 (here) or M15 */ | ||
201 | if (!mmc->nomux) | ||
202 | omap_cfg_reg(MMC_DAT2); | ||
203 | omap_cfg_reg(MMC_DAT3); | ||
204 | } | ||
205 | mmc1_conf = *mmc; | ||
206 | (void) platform_device_register(&mmc_omap_device1); | ||
207 | } | ||
208 | |||
209 | #ifdef CONFIG_ARCH_OMAP16XX | ||
210 | /* block 2 is on newer chips, and has many pinout options */ | ||
211 | mmc = &mmc_conf->mmc[1]; | ||
212 | if (mmc->enabled) { | ||
213 | if (!mmc->nomux) { | ||
214 | omap_cfg_reg(Y8_1610_MMC2_CMD); | ||
215 | omap_cfg_reg(Y10_1610_MMC2_CLK); | ||
216 | omap_cfg_reg(R18_1610_MMC2_CLKIN); | ||
217 | omap_cfg_reg(W8_1610_MMC2_DAT0); | ||
218 | if (mmc->wire4) { | ||
219 | omap_cfg_reg(V8_1610_MMC2_DAT1); | ||
220 | omap_cfg_reg(W15_1610_MMC2_DAT2); | ||
221 | omap_cfg_reg(R10_1610_MMC2_DAT3); | ||
222 | } | ||
223 | |||
224 | /* These are needed for the level shifter */ | ||
225 | omap_cfg_reg(V9_1610_MMC2_CMDDIR); | ||
226 | omap_cfg_reg(V5_1610_MMC2_DATDIR0); | ||
227 | omap_cfg_reg(W19_1610_MMC2_DATDIR1); | ||
228 | } | ||
229 | |||
230 | /* Feedback clock must be set on OMAP-1710 MMC2 */ | ||
231 | if (cpu_is_omap1710()) | ||
232 | omap_writel(omap_readl(MOD_CONF_CTRL_1) | (1 << 24), | ||
233 | MOD_CONF_CTRL_1); | ||
234 | mmc2_conf = *mmc; | ||
235 | (void) platform_device_register(&mmc_omap_device2); | ||
236 | } | ||
237 | #endif | ||
238 | return; | ||
239 | } | ||
240 | #else | ||
241 | static inline void omap_init_mmc(void) {} | ||
242 | #endif | ||
243 | |||
244 | #if defined(CONFIG_OMAP_RTC) || defined(CONFIG_OMAP_RTC) | 64 | #if defined(CONFIG_OMAP_RTC) || defined(CONFIG_OMAP_RTC) |
245 | 65 | ||
246 | #define OMAP_RTC_BASE 0xfffb4800 | 66 | #define OMAP_RTC_BASE 0xfffb4800 |
@@ -279,38 +99,6 @@ static void omap_init_rtc(void) | |||
279 | static inline void omap_init_rtc(void) {} | 99 | static inline void omap_init_rtc(void) {} |
280 | #endif | 100 | #endif |
281 | 101 | ||
282 | /*-------------------------------------------------------------------------*/ | ||
283 | |||
284 | #if defined(CONFIG_OMAP16XX_WATCHDOG) || defined(CONFIG_OMAP16XX_WATCHDOG_MODULE) | ||
285 | |||
286 | #define OMAP_WDT_BASE 0xfffeb000 | ||
287 | |||
288 | static struct resource wdt_resources[] = { | ||
289 | { | ||
290 | .start = OMAP_WDT_BASE, | ||
291 | .end = OMAP_WDT_BASE + 0x4f, | ||
292 | .flags = IORESOURCE_MEM, | ||
293 | }, | ||
294 | }; | ||
295 | |||
296 | static struct platform_device omap_wdt_device = { | ||
297 | .name = "omap1610_wdt", | ||
298 | .id = -1, | ||
299 | .dev = { | ||
300 | .release = omap_nop_release, | ||
301 | }, | ||
302 | .num_resources = ARRAY_SIZE(wdt_resources), | ||
303 | .resource = wdt_resources, | ||
304 | }; | ||
305 | |||
306 | static void omap_init_wdt(void) | ||
307 | { | ||
308 | (void) platform_device_register(&omap_wdt_device); | ||
309 | } | ||
310 | #else | ||
311 | static inline void omap_init_wdt(void) {} | ||
312 | #endif | ||
313 | |||
314 | 102 | ||
315 | /*-------------------------------------------------------------------------*/ | 103 | /*-------------------------------------------------------------------------*/ |
316 | 104 | ||
@@ -334,18 +122,15 @@ static inline void omap_init_wdt(void) {} | |||
334 | * may be handled by the boot loader, and drivers should expect it will | 122 | * may be handled by the boot loader, and drivers should expect it will |
335 | * normally have been done by the time they're probed. | 123 | * normally have been done by the time they're probed. |
336 | */ | 124 | */ |
337 | static int __init omap_init_devices(void) | 125 | static int __init omap1_init_devices(void) |
338 | { | 126 | { |
339 | /* please keep these calls, and their implementations above, | 127 | /* please keep these calls, and their implementations above, |
340 | * in alphabetical order so they're easier to sort through. | 128 | * in alphabetical order so they're easier to sort through. |
341 | */ | 129 | */ |
342 | omap_init_i2c(); | ||
343 | omap_init_irda(); | 130 | omap_init_irda(); |
344 | omap_init_mmc(); | ||
345 | omap_init_rtc(); | 131 | omap_init_rtc(); |
346 | omap_init_wdt(); | ||
347 | 132 | ||
348 | return 0; | 133 | return 0; |
349 | } | 134 | } |
350 | arch_initcall(omap_init_devices); | 135 | arch_initcall(omap1_init_devices); |
351 | 136 | ||
diff --git a/arch/arm/mach-omap1/id.c b/arch/arm/mach-omap1/id.c index 986c3b7e09bb..5c637c048368 100644 --- a/arch/arm/mach-omap1/id.c +++ b/arch/arm/mach-omap1/id.c | |||
@@ -18,6 +18,13 @@ | |||
18 | 18 | ||
19 | #include <asm/io.h> | 19 | #include <asm/io.h> |
20 | 20 | ||
21 | #define OMAP_DIE_ID_0 0xfffe1800 | ||
22 | #define OMAP_DIE_ID_1 0xfffe1804 | ||
23 | #define OMAP_PRODUCTION_ID_0 0xfffe2000 | ||
24 | #define OMAP_PRODUCTION_ID_1 0xfffe2004 | ||
25 | #define OMAP32_ID_0 0xfffed400 | ||
26 | #define OMAP32_ID_1 0xfffed404 | ||
27 | |||
21 | struct omap_id { | 28 | struct omap_id { |
22 | u16 jtag_id; /* Used to determine OMAP type */ | 29 | u16 jtag_id; /* Used to determine OMAP type */ |
23 | u8 die_rev; /* Processor revision */ | 30 | u8 die_rev; /* Processor revision */ |
@@ -27,6 +34,7 @@ struct omap_id { | |||
27 | 34 | ||
28 | /* Register values to detect the OMAP version */ | 35 | /* Register values to detect the OMAP version */ |
29 | static struct omap_id omap_ids[] __initdata = { | 36 | static struct omap_id omap_ids[] __initdata = { |
37 | { .jtag_id = 0xb574, .die_rev = 0x2, .omap_id = 0x03310315, .type = 0x03100000}, | ||
30 | { .jtag_id = 0x355f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300100}, | 38 | { .jtag_id = 0x355f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300100}, |
31 | { .jtag_id = 0xb55f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300300}, | 39 | { .jtag_id = 0xb55f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300300}, |
32 | { .jtag_id = 0xb470, .die_rev = 0x0, .omap_id = 0x03310100, .type = 0x15100000}, | 40 | { .jtag_id = 0xb470, .die_rev = 0x0, .omap_id = 0x03310100, .type = 0x15100000}, |
@@ -164,6 +172,7 @@ void __init omap_check_revision(void) | |||
164 | case 0x07: | 172 | case 0x07: |
165 | system_rev |= 0x07; | 173 | system_rev |= 0x07; |
166 | break; | 174 | break; |
175 | case 0x03: | ||
167 | case 0x15: | 176 | case 0x15: |
168 | system_rev |= 0x15; | 177 | system_rev |= 0x15; |
169 | break; | 178 | break; |
diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c index 79fb86535ebc..a7a19f75b9e1 100644 --- a/arch/arm/mach-omap1/io.c +++ b/arch/arm/mach-omap1/io.c | |||
@@ -15,9 +15,10 @@ | |||
15 | 15 | ||
16 | #include <asm/mach/map.h> | 16 | #include <asm/mach/map.h> |
17 | #include <asm/io.h> | 17 | #include <asm/io.h> |
18 | #include <asm/arch/mux.h> | ||
18 | #include <asm/arch/tc.h> | 19 | #include <asm/arch/tc.h> |
19 | 20 | ||
20 | extern int clk_init(void); | 21 | extern int omap1_clk_init(void); |
21 | extern void omap_check_revision(void); | 22 | extern void omap_check_revision(void); |
22 | extern void omap_sram_init(void); | 23 | extern void omap_sram_init(void); |
23 | 24 | ||
@@ -50,7 +51,7 @@ static struct map_desc omap730_io_desc[] __initdata = { | |||
50 | }; | 51 | }; |
51 | #endif | 52 | #endif |
52 | 53 | ||
53 | #ifdef CONFIG_ARCH_OMAP1510 | 54 | #ifdef CONFIG_ARCH_OMAP15XX |
54 | static struct map_desc omap1510_io_desc[] __initdata = { | 55 | static struct map_desc omap1510_io_desc[] __initdata = { |
55 | { | 56 | { |
56 | .virtual = OMAP1510_DSP_BASE, | 57 | .virtual = OMAP1510_DSP_BASE, |
@@ -98,7 +99,7 @@ static void __init _omap_map_io(void) | |||
98 | iotable_init(omap730_io_desc, ARRAY_SIZE(omap730_io_desc)); | 99 | iotable_init(omap730_io_desc, ARRAY_SIZE(omap730_io_desc)); |
99 | } | 100 | } |
100 | #endif | 101 | #endif |
101 | #ifdef CONFIG_ARCH_OMAP1510 | 102 | #ifdef CONFIG_ARCH_OMAP15XX |
102 | if (cpu_is_omap1510()) { | 103 | if (cpu_is_omap1510()) { |
103 | iotable_init(omap1510_io_desc, ARRAY_SIZE(omap1510_io_desc)); | 104 | iotable_init(omap1510_io_desc, ARRAY_SIZE(omap1510_io_desc)); |
104 | } | 105 | } |
@@ -119,7 +120,7 @@ static void __init _omap_map_io(void) | |||
119 | 120 | ||
120 | /* Must init clocks early to assure that timer interrupt works | 121 | /* Must init clocks early to assure that timer interrupt works |
121 | */ | 122 | */ |
122 | clk_init(); | 123 | omap1_clk_init(); |
123 | } | 124 | } |
124 | 125 | ||
125 | /* | 126 | /* |
@@ -127,7 +128,9 @@ static void __init _omap_map_io(void) | |||
127 | */ | 128 | */ |
128 | void __init omap_map_common_io(void) | 129 | void __init omap_map_common_io(void) |
129 | { | 130 | { |
130 | if (!initialized) | 131 | if (!initialized) { |
131 | _omap_map_io(); | 132 | _omap_map_io(); |
133 | omap1_mux_init(); | ||
134 | } | ||
132 | } | 135 | } |
133 | 136 | ||
diff --git a/arch/arm/mach-omap1/irq.c b/arch/arm/mach-omap1/irq.c index 192ce6055faa..ed65a7d2e941 100644 --- a/arch/arm/mach-omap1/irq.c +++ b/arch/arm/mach-omap1/irq.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #include <asm/irq.h> | 47 | #include <asm/irq.h> |
48 | #include <asm/mach/irq.h> | 48 | #include <asm/mach/irq.h> |
49 | #include <asm/arch/gpio.h> | 49 | #include <asm/arch/gpio.h> |
50 | #include <asm/arch/cpu.h> | ||
50 | 51 | ||
51 | #include <asm/io.h> | 52 | #include <asm/io.h> |
52 | 53 | ||
@@ -147,11 +148,15 @@ static struct omap_irq_bank omap730_irq_banks[] = { | |||
147 | }; | 148 | }; |
148 | #endif | 149 | #endif |
149 | 150 | ||
150 | #ifdef CONFIG_ARCH_OMAP1510 | 151 | #ifdef CONFIG_ARCH_OMAP15XX |
151 | static struct omap_irq_bank omap1510_irq_banks[] = { | 152 | static struct omap_irq_bank omap1510_irq_banks[] = { |
152 | { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3febfff }, | 153 | { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3febfff }, |
153 | { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xffbfffed }, | 154 | { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xffbfffed }, |
154 | }; | 155 | }; |
156 | static struct omap_irq_bank omap310_irq_banks[] = { | ||
157 | { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3faefc3 }, | ||
158 | { .base_reg = OMAP_IH2_BASE, .trigger_map = 0x65b3c061 }, | ||
159 | }; | ||
155 | #endif | 160 | #endif |
156 | 161 | ||
157 | #if defined(CONFIG_ARCH_OMAP16XX) | 162 | #if defined(CONFIG_ARCH_OMAP16XX) |
@@ -181,11 +186,15 @@ void __init omap_init_irq(void) | |||
181 | irq_bank_count = ARRAY_SIZE(omap730_irq_banks); | 186 | irq_bank_count = ARRAY_SIZE(omap730_irq_banks); |
182 | } | 187 | } |
183 | #endif | 188 | #endif |
184 | #ifdef CONFIG_ARCH_OMAP1510 | 189 | #ifdef CONFIG_ARCH_OMAP15XX |
185 | if (cpu_is_omap1510()) { | 190 | if (cpu_is_omap1510()) { |
186 | irq_banks = omap1510_irq_banks; | 191 | irq_banks = omap1510_irq_banks; |
187 | irq_bank_count = ARRAY_SIZE(omap1510_irq_banks); | 192 | irq_bank_count = ARRAY_SIZE(omap1510_irq_banks); |
188 | } | 193 | } |
194 | if (cpu_is_omap310()) { | ||
195 | irq_banks = omap310_irq_banks; | ||
196 | irq_bank_count = ARRAY_SIZE(omap310_irq_banks); | ||
197 | } | ||
189 | #endif | 198 | #endif |
190 | #if defined(CONFIG_ARCH_OMAP16XX) | 199 | #if defined(CONFIG_ARCH_OMAP16XX) |
191 | if (cpu_is_omap16xx()) { | 200 | if (cpu_is_omap16xx()) { |
@@ -226,9 +235,11 @@ void __init omap_init_irq(void) | |||
226 | } | 235 | } |
227 | 236 | ||
228 | /* Unmask level 2 handler */ | 237 | /* Unmask level 2 handler */ |
229 | if (cpu_is_omap730()) { | 238 | |
239 | if (cpu_is_omap730()) | ||
230 | omap_unmask_irq(INT_730_IH2_IRQ); | 240 | omap_unmask_irq(INT_730_IH2_IRQ); |
231 | } else { | 241 | else if (cpu_is_omap1510()) |
232 | omap_unmask_irq(INT_IH2_IRQ); | 242 | omap_unmask_irq(INT_1510_IH2_IRQ); |
233 | } | 243 | else if (cpu_is_omap16xx()) |
244 | omap_unmask_irq(INT_1610_IH2_IRQ); | ||
234 | } | 245 | } |
diff --git a/arch/arm/mach-omap1/leds-h2p2-debug.c b/arch/arm/mach-omap1/leds-h2p2-debug.c index 399010c14036..650650815915 100644 --- a/arch/arm/mach-omap1/leds-h2p2-debug.c +++ b/arch/arm/mach-omap1/leds-h2p2-debug.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <asm/hardware.h> | 18 | #include <asm/hardware.h> |
19 | #include <asm/leds.h> | 19 | #include <asm/leds.h> |
20 | #include <asm/system.h> | 20 | #include <asm/system.h> |
21 | #include <asm/mach-types.h> | ||
21 | 22 | ||
22 | #include <asm/arch/fpga.h> | 23 | #include <asm/arch/fpga.h> |
23 | #include <asm/arch/gpio.h> | 24 | #include <asm/arch/gpio.h> |
@@ -63,14 +64,19 @@ void h2p2_dbg_leds_event(led_event_t evt) | |||
63 | case led_stop: | 64 | case led_stop: |
64 | case led_halted: | 65 | case led_halted: |
65 | /* all leds off during suspend or shutdown */ | 66 | /* all leds off during suspend or shutdown */ |
66 | omap_set_gpio_dataout(GPIO_TIMER, 0); | 67 | |
67 | omap_set_gpio_dataout(GPIO_IDLE, 0); | 68 | if (! machine_is_omap_perseus2()) { |
69 | omap_set_gpio_dataout(GPIO_TIMER, 0); | ||
70 | omap_set_gpio_dataout(GPIO_IDLE, 0); | ||
71 | } | ||
72 | |||
68 | __raw_writew(~0, &fpga->leds); | 73 | __raw_writew(~0, &fpga->leds); |
69 | led_state &= ~LED_STATE_ENABLED; | 74 | led_state &= ~LED_STATE_ENABLED; |
70 | if (evt == led_halted) { | 75 | if (evt == led_halted) { |
71 | iounmap(fpga); | 76 | iounmap(fpga); |
72 | fpga = NULL; | 77 | fpga = NULL; |
73 | } | 78 | } |
79 | |||
74 | goto done; | 80 | goto done; |
75 | 81 | ||
76 | case led_claim: | 82 | case led_claim: |
@@ -85,18 +91,37 @@ void h2p2_dbg_leds_event(led_event_t evt) | |||
85 | #ifdef CONFIG_LEDS_TIMER | 91 | #ifdef CONFIG_LEDS_TIMER |
86 | case led_timer: | 92 | case led_timer: |
87 | led_state ^= LED_TIMER_ON; | 93 | led_state ^= LED_TIMER_ON; |
88 | omap_set_gpio_dataout(GPIO_TIMER, led_state & LED_TIMER_ON); | 94 | |
89 | goto done; | 95 | if (machine_is_omap_perseus2()) |
96 | hw_led_state ^= H2P2_DBG_FPGA_P2_LED_TIMER; | ||
97 | else { | ||
98 | omap_set_gpio_dataout(GPIO_TIMER, led_state & LED_TIMER_ON); | ||
99 | goto done; | ||
100 | } | ||
101 | |||
102 | break; | ||
90 | #endif | 103 | #endif |
91 | 104 | ||
92 | #ifdef CONFIG_LEDS_CPU | 105 | #ifdef CONFIG_LEDS_CPU |
93 | case led_idle_start: | 106 | case led_idle_start: |
94 | omap_set_gpio_dataout(GPIO_IDLE, 1); | 107 | if (machine_is_omap_perseus2()) |
95 | goto done; | 108 | hw_led_state |= H2P2_DBG_FPGA_P2_LED_IDLE; |
109 | else { | ||
110 | omap_set_gpio_dataout(GPIO_IDLE, 1); | ||
111 | goto done; | ||
112 | } | ||
113 | |||
114 | break; | ||
96 | 115 | ||
97 | case led_idle_end: | 116 | case led_idle_end: |
98 | omap_set_gpio_dataout(GPIO_IDLE, 0); | 117 | if (machine_is_omap_perseus2()) |
99 | goto done; | 118 | hw_led_state &= ~H2P2_DBG_FPGA_P2_LED_IDLE; |
119 | else { | ||
120 | omap_set_gpio_dataout(GPIO_IDLE, 0); | ||
121 | goto done; | ||
122 | } | ||
123 | |||
124 | break; | ||
100 | #endif | 125 | #endif |
101 | 126 | ||
102 | case led_green_on: | 127 | case led_green_on: |
@@ -135,7 +160,7 @@ void h2p2_dbg_leds_event(led_event_t evt) | |||
135 | /* | 160 | /* |
136 | * Actually burn the LEDs | 161 | * Actually burn the LEDs |
137 | */ | 162 | */ |
138 | if (led_state & LED_STATE_CLAIMED) | 163 | if (led_state & LED_STATE_ENABLED) |
139 | __raw_writew(~hw_led_state, &fpga->leds); | 164 | __raw_writew(~hw_led_state, &fpga->leds); |
140 | 165 | ||
141 | done: | 166 | done: |
diff --git a/arch/arm/mach-omap1/leds.c b/arch/arm/mach-omap1/leds.c index 5c6b1bb6e722..3f9dcac4fd41 100644 --- a/arch/arm/mach-omap1/leds.c +++ b/arch/arm/mach-omap1/leds.c | |||
@@ -33,7 +33,6 @@ omap_leds_init(void) | |||
33 | 33 | ||
34 | if (machine_is_omap_h2() | 34 | if (machine_is_omap_h2() |
35 | || machine_is_omap_h3() | 35 | || machine_is_omap_h3() |
36 | || machine_is_omap_perseus2() | ||
37 | #ifdef CONFIG_OMAP_OSK_MISTRAL | 36 | #ifdef CONFIG_OMAP_OSK_MISTRAL |
38 | || machine_is_omap_osk() | 37 | || machine_is_omap_osk() |
39 | #endif | 38 | #endif |
diff --git a/arch/arm/mach-omap1/mux.c b/arch/arm/mach-omap1/mux.c new file mode 100644 index 000000000000..d4b8d624e742 --- /dev/null +++ b/arch/arm/mach-omap1/mux.c | |||
@@ -0,0 +1,289 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-omap1/mux.c | ||
3 | * | ||
4 | * OMAP1 pin multiplexing configurations | ||
5 | * | ||
6 | * Copyright (C) 2003 - 2005 Nokia Corporation | ||
7 | * | ||
8 | * Written by Tony Lindgren <tony.lindgren@nokia.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
24 | */ | ||
25 | #include <linux/config.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <asm/system.h> | ||
29 | #include <asm/io.h> | ||
30 | #include <linux/spinlock.h> | ||
31 | |||
32 | #include <asm/arch/mux.h> | ||
33 | |||
34 | #ifdef CONFIG_OMAP_MUX | ||
35 | |||
36 | #ifdef CONFIG_ARCH_OMAP730 | ||
37 | struct pin_config __initdata_or_module omap730_pins[] = { | ||
38 | MUX_CFG_730("E2_730_KBR0", 12, 21, 0, 0, 20, 1, NA, 0, 0) | ||
39 | MUX_CFG_730("J7_730_KBR1", 12, 25, 0, 0, 24, 1, NA, 0, 0) | ||
40 | MUX_CFG_730("E1_730_KBR2", 12, 29, 0, 0, 28, 1, NA, 0, 0) | ||
41 | MUX_CFG_730("F3_730_KBR3", 13, 1, 0, 0, 0, 1, NA, 0, 0) | ||
42 | MUX_CFG_730("D2_730_KBR4", 13, 5, 0, 0, 4, 1, NA, 0, 0) | ||
43 | MUX_CFG_730("C2_730_KBC0", 13, 9, 0, 0, 8, 1, NA, 0, 0) | ||
44 | MUX_CFG_730("D3_730_KBC1", 13, 13, 0, 0, 12, 1, NA, 0, 0) | ||
45 | MUX_CFG_730("E4_730_KBC2", 13, 17, 0, 0, 16, 1, NA, 0, 0) | ||
46 | MUX_CFG_730("F4_730_KBC3", 13, 21, 0, 0, 20, 1, NA, 0, 0) | ||
47 | MUX_CFG_730("E3_730_KBC4", 13, 25, 0, 0, 24, 1, NA, 0, 0) | ||
48 | }; | ||
49 | #endif | ||
50 | |||
51 | #if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) | ||
52 | struct pin_config __initdata_or_module omap1xxx_pins[] = { | ||
53 | /* | ||
54 | * description mux mode mux pull pull pull pu_pd pu dbg | ||
55 | * reg offset mode reg bit ena reg | ||
56 | */ | ||
57 | MUX_CFG("UART1_TX", 9, 21, 1, 2, 3, 0, NA, 0, 0) | ||
58 | MUX_CFG("UART1_RTS", 9, 12, 1, 2, 0, 0, NA, 0, 0) | ||
59 | |||
60 | /* UART2 (COM_UART_GATING), conflicts with USB2 */ | ||
61 | MUX_CFG("UART2_TX", C, 27, 1, 3, 3, 0, NA, 0, 0) | ||
62 | MUX_CFG("UART2_RX", C, 18, 0, 3, 1, 1, NA, 0, 0) | ||
63 | MUX_CFG("UART2_CTS", C, 21, 0, 3, 1, 1, NA, 0, 0) | ||
64 | MUX_CFG("UART2_RTS", C, 24, 1, 3, 2, 0, NA, 0, 0) | ||
65 | |||
66 | /* UART3 (GIGA_UART_GATING) */ | ||
67 | MUX_CFG("UART3_TX", 6, 0, 1, 0, 30, 0, NA, 0, 0) | ||
68 | MUX_CFG("UART3_RX", 6, 3, 0, 0, 31, 1, NA, 0, 0) | ||
69 | MUX_CFG("UART3_CTS", 5, 12, 2, 0, 24, 0, NA, 0, 0) | ||
70 | MUX_CFG("UART3_RTS", 5, 15, 2, 0, 25, 0, NA, 0, 0) | ||
71 | MUX_CFG("UART3_CLKREQ", 9, 27, 0, 2, 5, 0, NA, 0, 0) | ||
72 | MUX_CFG("UART3_BCLK", A, 0, 0, 2, 6, 0, NA, 0, 0) | ||
73 | MUX_CFG("Y15_1610_UART3_RTS", A, 0, 1, 2, 6, 0, NA, 0, 0) | ||
74 | |||
75 | /* PWT & PWL, conflicts with UART3 */ | ||
76 | MUX_CFG("PWT", 6, 0, 2, 0, 30, 0, NA, 0, 0) | ||
77 | MUX_CFG("PWL", 6, 3, 1, 0, 31, 1, NA, 0, 0) | ||
78 | |||
79 | /* USB internal master generic */ | ||
80 | MUX_CFG("R18_USB_VBUS", 7, 9, 2, 1, 11, 0, NA, 0, 1) | ||
81 | MUX_CFG("R18_1510_USB_GPIO0", 7, 9, 0, 1, 11, 1, NA, 0, 1) | ||
82 | /* works around erratum: W4_USB_PUEN and W4_USB_PUDIS are switched! */ | ||
83 | MUX_CFG("W4_USB_PUEN", D, 3, 3, 3, 5, 1, NA, 0, 1) | ||
84 | MUX_CFG("W4_USB_CLKO", D, 3, 1, 3, 5, 0, NA, 0, 1) | ||
85 | MUX_CFG("W4_USB_HIGHZ", D, 3, 4, 3, 5, 0, 3, 0, 1) | ||
86 | MUX_CFG("W4_GPIO58", D, 3, 7, 3, 5, 0, 3, 0, 1) | ||
87 | |||
88 | /* USB1 master */ | ||
89 | MUX_CFG("USB1_SUSP", 8, 27, 2, 1, 27, 0, NA, 0, 1) | ||
90 | MUX_CFG("USB1_SE0", 9, 0, 2, 1, 28, 0, NA, 0, 1) | ||
91 | MUX_CFG("W13_1610_USB1_SE0", 9, 0, 4, 1, 28, 0, NA, 0, 1) | ||
92 | MUX_CFG("USB1_TXEN", 9, 3, 2, 1, 29, 0, NA, 0, 1) | ||
93 | MUX_CFG("USB1_TXD", 9, 24, 1, 2, 4, 0, NA, 0, 1) | ||
94 | MUX_CFG("USB1_VP", A, 3, 1, 2, 7, 0, NA, 0, 1) | ||
95 | MUX_CFG("USB1_VM", A, 6, 1, 2, 8, 0, NA, 0, 1) | ||
96 | MUX_CFG("USB1_RCV", A, 9, 1, 2, 9, 0, NA, 0, 1) | ||
97 | MUX_CFG("USB1_SPEED", A, 12, 2, 2, 10, 0, NA, 0, 1) | ||
98 | MUX_CFG("R13_1610_USB1_SPEED", A, 12, 5, 2, 10, 0, NA, 0, 1) | ||
99 | MUX_CFG("R13_1710_USB1_SEO", A, 12, 5, 2, 10, 0, NA, 0, 1) | ||
100 | |||
101 | /* USB2 master */ | ||
102 | MUX_CFG("USB2_SUSP", B, 3, 1, 2, 17, 0, NA, 0, 1) | ||
103 | MUX_CFG("USB2_VP", B, 6, 1, 2, 18, 0, NA, 0, 1) | ||
104 | MUX_CFG("USB2_TXEN", B, 9, 1, 2, 19, 0, NA, 0, 1) | ||
105 | MUX_CFG("USB2_VM", C, 18, 1, 3, 0, 0, NA, 0, 1) | ||
106 | MUX_CFG("USB2_RCV", C, 21, 1, 3, 1, 0, NA, 0, 1) | ||
107 | MUX_CFG("USB2_SE0", C, 24, 2, 3, 2, 0, NA, 0, 1) | ||
108 | MUX_CFG("USB2_TXD", C, 27, 2, 3, 3, 0, NA, 0, 1) | ||
109 | |||
110 | /* OMAP-1510 GPIO */ | ||
111 | MUX_CFG("R18_1510_GPIO0", 7, 9, 0, 1, 11, 1, 0, 0, 1) | ||
112 | MUX_CFG("R19_1510_GPIO1", 7, 6, 0, 1, 10, 1, 0, 0, 1) | ||
113 | MUX_CFG("M14_1510_GPIO2", 7, 3, 0, 1, 9, 1, 0, 0, 1) | ||
114 | |||
115 | /* OMAP1610 GPIO */ | ||
116 | MUX_CFG("P18_1610_GPIO3", 7, 0, 0, 1, 8, 0, NA, 0, 1) | ||
117 | MUX_CFG("Y15_1610_GPIO17", A, 0, 7, 2, 6, 0, NA, 0, 1) | ||
118 | |||
119 | /* OMAP-1710 GPIO */ | ||
120 | MUX_CFG("R18_1710_GPIO0", 7, 9, 0, 1, 11, 1, 1, 1, 1) | ||
121 | MUX_CFG("V2_1710_GPIO10", F, 27, 1, 4, 3, 1, 4, 1, 1) | ||
122 | MUX_CFG("N21_1710_GPIO14", 6, 9, 0, 1, 1, 1, 1, 1, 1) | ||
123 | MUX_CFG("W15_1710_GPIO40", 9, 27, 7, 2, 5, 1, 2, 1, 1) | ||
124 | |||
125 | /* MPUIO */ | ||
126 | MUX_CFG("MPUIO2", 7, 18, 0, 1, 14, 1, NA, 0, 1) | ||
127 | MUX_CFG("N15_1610_MPUIO2", 7, 18, 0, 1, 14, 1, 1, 0, 1) | ||
128 | MUX_CFG("MPUIO4", 7, 15, 0, 1, 13, 1, NA, 0, 1) | ||
129 | MUX_CFG("MPUIO5", 7, 12, 0, 1, 12, 1, NA, 0, 1) | ||
130 | |||
131 | MUX_CFG("T20_1610_MPUIO5", 7, 12, 0, 1, 12, 0, 3, 0, 1) | ||
132 | MUX_CFG("W11_1610_MPUIO6", 10, 15, 2, 3, 8, 0, 3, 0, 1) | ||
133 | MUX_CFG("V10_1610_MPUIO7", A, 24, 2, 2, 14, 0, 2, 0, 1) | ||
134 | MUX_CFG("W11_1610_MPUIO9", 10, 15, 1, 3, 8, 0, 3, 0, 1) | ||
135 | MUX_CFG("V10_1610_MPUIO10", A, 24, 1, 2, 14, 0, 2, 0, 1) | ||
136 | MUX_CFG("W10_1610_MPUIO11", A, 18, 2, 2, 11, 0, 2, 0, 1) | ||
137 | MUX_CFG("E20_1610_MPUIO13", 3, 21, 1, 0, 7, 0, 0, 0, 1) | ||
138 | MUX_CFG("U20_1610_MPUIO14", 9, 6, 6, 0, 30, 0, 0, 0, 1) | ||
139 | MUX_CFG("E19_1610_MPUIO15", 3, 18, 1, 0, 6, 0, 0, 0, 1) | ||
140 | |||
141 | /* MCBSP2 */ | ||
142 | MUX_CFG("MCBSP2_CLKR", C, 6, 0, 2, 27, 1, NA, 0, 1) | ||
143 | MUX_CFG("MCBSP2_CLKX", C, 9, 0, 2, 29, 1, NA, 0, 1) | ||
144 | MUX_CFG("MCBSP2_DR", C, 0, 0, 2, 26, 1, NA, 0, 1) | ||
145 | MUX_CFG("MCBSP2_DX", C, 15, 0, 2, 31, 1, NA, 0, 1) | ||
146 | MUX_CFG("MCBSP2_FSR", C, 12, 0, 2, 30, 1, NA, 0, 1) | ||
147 | MUX_CFG("MCBSP2_FSX", C, 3, 0, 2, 27, 1, NA, 0, 1) | ||
148 | |||
149 | /* MCBSP3 NOTE: Mode must 1 for clock */ | ||
150 | MUX_CFG("MCBSP3_CLKX", 9, 3, 1, 1, 29, 0, NA, 0, 1) | ||
151 | |||
152 | /* Misc ballouts */ | ||
153 | MUX_CFG("BALLOUT_V8_ARMIO3", B, 18, 0, 2, 25, 1, NA, 0, 1) | ||
154 | MUX_CFG("N20_HDQ", 6, 18, 1, 1, 4, 0, 1, 4, 0) | ||
155 | |||
156 | /* OMAP-1610 MMC2 */ | ||
157 | MUX_CFG("W8_1610_MMC2_DAT0", B, 21, 6, 2, 23, 1, 2, 1, 1) | ||
158 | MUX_CFG("V8_1610_MMC2_DAT1", B, 27, 6, 2, 25, 1, 2, 1, 1) | ||
159 | MUX_CFG("W15_1610_MMC2_DAT2", 9, 12, 6, 2, 5, 1, 2, 1, 1) | ||
160 | MUX_CFG("R10_1610_MMC2_DAT3", B, 18, 6, 2, 22, 1, 2, 1, 1) | ||
161 | MUX_CFG("Y10_1610_MMC2_CLK", B, 3, 6, 2, 17, 0, 2, 0, 1) | ||
162 | MUX_CFG("Y8_1610_MMC2_CMD", B, 24, 6, 2, 24, 1, 2, 1, 1) | ||
163 | MUX_CFG("V9_1610_MMC2_CMDDIR", B, 12, 6, 2, 20, 0, 2, 1, 1) | ||
164 | MUX_CFG("V5_1610_MMC2_DATDIR0", B, 15, 6, 2, 21, 0, 2, 1, 1) | ||
165 | MUX_CFG("W19_1610_MMC2_DATDIR1", 8, 15, 6, 1, 23, 0, 1, 1, 1) | ||
166 | MUX_CFG("R18_1610_MMC2_CLKIN", 7, 9, 6, 1, 11, 0, 1, 11, 1) | ||
167 | |||
168 | /* OMAP-1610 External Trace Interface */ | ||
169 | MUX_CFG("M19_1610_ETM_PSTAT0", 5, 27, 1, 0, 29, 0, 0, 0, 1) | ||
170 | MUX_CFG("L15_1610_ETM_PSTAT1", 5, 24, 1, 0, 28, 0, 0, 0, 1) | ||
171 | MUX_CFG("L18_1610_ETM_PSTAT2", 5, 21, 1, 0, 27, 0, 0, 0, 1) | ||
172 | MUX_CFG("L19_1610_ETM_D0", 5, 18, 1, 0, 26, 0, 0, 0, 1) | ||
173 | MUX_CFG("J19_1610_ETM_D6", 5, 0, 1, 0, 20, 0, 0, 0, 1) | ||
174 | MUX_CFG("J18_1610_ETM_D7", 5, 27, 1, 0, 19, 0, 0, 0, 1) | ||
175 | |||
176 | /* OMAP16XX GPIO */ | ||
177 | MUX_CFG("P20_1610_GPIO4", 6, 27, 0, 1, 7, 0, 1, 1, 1) | ||
178 | MUX_CFG("V9_1610_GPIO7", B, 12, 1, 2, 20, 0, 2, 1, 1) | ||
179 | MUX_CFG("W8_1610_GPIO9", B, 21, 0, 2, 23, 0, 2, 1, 1) | ||
180 | MUX_CFG("N20_1610_GPIO11", 6, 18, 0, 1, 4, 0, 1, 1, 1) | ||
181 | MUX_CFG("N19_1610_GPIO13", 6, 12, 0, 1, 2, 0, 1, 1, 1) | ||
182 | MUX_CFG("P10_1610_GPIO22", C, 0, 7, 2, 26, 0, 2, 1, 1) | ||
183 | MUX_CFG("V5_1610_GPIO24", B, 15, 7, 2, 21, 0, 2, 1, 1) | ||
184 | MUX_CFG("AA20_1610_GPIO_41", 9, 9, 7, 1, 31, 0, 1, 1, 1) | ||
185 | MUX_CFG("W19_1610_GPIO48", 8, 15, 7, 1, 23, 1, 1, 0, 1) | ||
186 | MUX_CFG("M7_1610_GPIO62", 10, 0, 0, 4, 24, 0, 4, 0, 1) | ||
187 | MUX_CFG("V14_16XX_GPIO37", 9, 18, 7, 2, 2, 0, 2, 2, 0) | ||
188 | MUX_CFG("R9_16XX_GPIO18", C, 18, 7, 3, 0, 0, 3, 0, 0) | ||
189 | MUX_CFG("L14_16XX_GPIO49", 6, 3, 7, 0, 31, 0, 0, 31, 0) | ||
190 | |||
191 | /* OMAP-1610 uWire */ | ||
192 | MUX_CFG("V19_1610_UWIRE_SCLK", 8, 6, 0, 1, 20, 0, 1, 1, 1) | ||
193 | MUX_CFG("U18_1610_UWIRE_SDI", 8, 0, 0, 1, 18, 0, 1, 1, 1) | ||
194 | MUX_CFG("W21_1610_UWIRE_SDO", 8, 3, 0, 1, 19, 0, 1, 1, 1) | ||
195 | MUX_CFG("N14_1610_UWIRE_CS0", 8, 9, 1, 1, 21, 0, 1, 1, 1) | ||
196 | MUX_CFG("P15_1610_UWIRE_CS3", 8, 12, 1, 1, 22, 0, 1, 1, 1) | ||
197 | MUX_CFG("N15_1610_UWIRE_CS1", 7, 18, 2, 1, 14, 0, NA, 0, 1) | ||
198 | |||
199 | /* OMAP-1610 Flash */ | ||
200 | MUX_CFG("L3_1610_FLASH_CS2B_OE",10, 6, 1, NA, 0, 0, NA, 0, 1) | ||
201 | MUX_CFG("M8_1610_FLASH_CS2B_WE",10, 3, 1, NA, 0, 0, NA, 0, 1) | ||
202 | |||
203 | /* First MMC interface, same on 1510, 1610 and 1710 */ | ||
204 | MUX_CFG("MMC_CMD", A, 27, 0, 2, 15, 1, 2, 1, 1) | ||
205 | MUX_CFG("MMC_DAT1", A, 24, 0, 2, 14, 1, 2, 1, 1) | ||
206 | MUX_CFG("MMC_DAT2", A, 18, 0, 2, 12, 1, 2, 1, 1) | ||
207 | MUX_CFG("MMC_DAT0", B, 0, 0, 2, 16, 1, 2, 1, 1) | ||
208 | MUX_CFG("MMC_CLK", A, 21, 0, NA, 0, 0, NA, 0, 1) | ||
209 | MUX_CFG("MMC_DAT3", 10, 15, 0, 3, 8, 1, 3, 1, 1) | ||
210 | MUX_CFG("M15_1710_MMC_CLKI", 6, 21, 2, 0, 0, 0, NA, 0, 1) | ||
211 | MUX_CFG("P19_1710_MMC_CMDDIR", 6, 24, 6, 0, 0, 0, NA, 0, 1) | ||
212 | MUX_CFG("P20_1710_MMC_DATDIR0", 6, 27, 5, 0, 0, 0, NA, 0, 1) | ||
213 | |||
214 | /* OMAP-1610 USB0 alternate configuration */ | ||
215 | MUX_CFG("W9_USB0_TXEN", B, 9, 5, 2, 19, 0, 2, 0, 1) | ||
216 | MUX_CFG("AA9_USB0_VP", B, 6, 5, 2, 18, 0, 2, 0, 1) | ||
217 | MUX_CFG("Y5_USB0_RCV", C, 21, 5, 3, 1, 0, 1, 0, 1) | ||
218 | MUX_CFG("R9_USB0_VM", C, 18, 5, 3, 0, 0, 3, 0, 1) | ||
219 | MUX_CFG("V6_USB0_TXD", C, 27, 5, 3, 3, 0, 3, 0, 1) | ||
220 | MUX_CFG("W5_USB0_SE0", C, 24, 5, 3, 2, 0, 3, 0, 1) | ||
221 | MUX_CFG("V9_USB0_SPEED", B, 12, 5, 2, 20, 0, 2, 0, 1) | ||
222 | MUX_CFG("Y10_USB0_SUSP", B, 3, 5, 2, 17, 0, 2, 0, 1) | ||
223 | |||
224 | /* USB2 interface */ | ||
225 | MUX_CFG("W9_USB2_TXEN", B, 9, 1, NA, 0, 0, NA, 0, 1) | ||
226 | MUX_CFG("AA9_USB2_VP", B, 6, 1, NA, 0, 0, NA, 0, 1) | ||
227 | MUX_CFG("Y5_USB2_RCV", C, 21, 1, NA, 0, 0, NA, 0, 1) | ||
228 | MUX_CFG("R9_USB2_VM", C, 18, 1, NA, 0, 0, NA, 0, 1) | ||
229 | MUX_CFG("V6_USB2_TXD", C, 27, 2, NA, 0, 0, NA, 0, 1) | ||
230 | MUX_CFG("W5_USB2_SE0", C, 24, 2, NA, 0, 0, NA, 0, 1) | ||
231 | |||
232 | /* 16XX UART */ | ||
233 | MUX_CFG("R13_1610_UART1_TX", A, 12, 6, 2, 10, 0, 2, 10, 1) | ||
234 | MUX_CFG("V14_16XX_UART1_RX", 9, 18, 0, 2, 2, 0, 2, 2, 1) | ||
235 | MUX_CFG("R14_1610_UART1_CTS", 9, 15, 0, 2, 1, 0, 2, 1, 1) | ||
236 | MUX_CFG("AA15_1610_UART1_RTS", 9, 12, 1, 2, 0, 0, 2, 0, 1) | ||
237 | MUX_CFG("R9_16XX_UART2_RX", C, 18, 0, 3, 0, 0, 3, 0, 1) | ||
238 | MUX_CFG("L14_16XX_UART3_RX", 6, 3, 0, 0, 31, 0, 0, 31, 1) | ||
239 | |||
240 | /* I2C interface */ | ||
241 | MUX_CFG("I2C_SCL", 7, 24, 0, NA, 0, 0, NA, 0, 0) | ||
242 | MUX_CFG("I2C_SDA", 7, 27, 0, NA, 0, 0, NA, 0, 0) | ||
243 | |||
244 | /* Keypad */ | ||
245 | MUX_CFG("F18_1610_KBC0", 3, 15, 0, 0, 5, 1, 0, 0, 0) | ||
246 | MUX_CFG("D20_1610_KBC1", 3, 12, 0, 0, 4, 1, 0, 0, 0) | ||
247 | MUX_CFG("D19_1610_KBC2", 3, 9, 0, 0, 3, 1, 0, 0, 0) | ||
248 | MUX_CFG("E18_1610_KBC3", 3, 6, 0, 0, 2, 1, 0, 0, 0) | ||
249 | MUX_CFG("C21_1610_KBC4", 3, 3, 0, 0, 1, 1, 0, 0, 0) | ||
250 | MUX_CFG("G18_1610_KBR0", 4, 0, 0, 0, 10, 1, 0, 1, 0) | ||
251 | MUX_CFG("F19_1610_KBR1", 3, 27, 0, 0, 9, 1, 0, 1, 0) | ||
252 | MUX_CFG("H14_1610_KBR2", 3, 24, 0, 0, 8, 1, 0, 1, 0) | ||
253 | MUX_CFG("E20_1610_KBR3", 3, 21, 0, 0, 7, 1, 0, 1, 0) | ||
254 | MUX_CFG("E19_1610_KBR4", 3, 18, 0, 0, 6, 1, 0, 1, 0) | ||
255 | MUX_CFG("N19_1610_KBR5", 6, 12, 1, 1, 2, 1, 1, 1, 0) | ||
256 | |||
257 | /* Power management */ | ||
258 | MUX_CFG("T20_1610_LOW_PWR", 7, 12, 1, NA, 0, 0, NA, 0, 0) | ||
259 | |||
260 | /* MCLK Settings */ | ||
261 | MUX_CFG("V5_1710_MCLK_ON", B, 15, 0, NA, 0, 0, NA, 0, 0) | ||
262 | MUX_CFG("V5_1710_MCLK_OFF", B, 15, 6, NA, 0, 0, NA, 0, 0) | ||
263 | MUX_CFG("R10_1610_MCLK_ON", B, 18, 0, NA, 22, 0, NA, 1, 0) | ||
264 | MUX_CFG("R10_1610_MCLK_OFF", B, 18, 6, 2, 22, 1, 2, 1, 1) | ||
265 | |||
266 | /* CompactFlash controller, conflicts with MMC1 */ | ||
267 | MUX_CFG("P11_1610_CF_CD2", A, 27, 3, 2, 15, 1, 2, 1, 1) | ||
268 | MUX_CFG("R11_1610_CF_IOIS16", B, 0, 3, 2, 16, 1, 2, 1, 1) | ||
269 | MUX_CFG("V10_1610_CF_IREQ", A, 24, 3, 2, 14, 0, 2, 0, 1) | ||
270 | MUX_CFG("W10_1610_CF_RESET", A, 18, 3, 2, 12, 1, 2, 1, 1) | ||
271 | MUX_CFG("W11_1610_CF_CD1", 10, 15, 3, 3, 8, 1, 3, 1, 1) | ||
272 | }; | ||
273 | #endif /* CONFIG_ARCH_OMAP15XX || CONFIG_ARCH_OMAP16XX */ | ||
274 | |||
275 | int __init omap1_mux_init(void) | ||
276 | { | ||
277 | |||
278 | #ifdef CONFIG_ARCH_OMAP730 | ||
279 | omap_mux_register(omap730_pins, ARRAY_SIZE(omap730_pins)); | ||
280 | #endif | ||
281 | |||
282 | #if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) | ||
283 | omap_mux_register(omap1xxx_pins, ARRAY_SIZE(omap1xxx_pins)); | ||
284 | #endif | ||
285 | |||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | #endif | ||
diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c index 40c4f7c40e73..6810cfb84462 100644 --- a/arch/arm/mach-omap1/serial.c +++ b/arch/arm/mach-omap1/serial.c | |||
@@ -109,9 +109,10 @@ static struct platform_device serial_device = { | |||
109 | * By default UART2 does not work on Innovator-1510 if you have | 109 | * By default UART2 does not work on Innovator-1510 if you have |
110 | * USB OHCI enabled. To use UART2, you must disable USB2 first. | 110 | * USB OHCI enabled. To use UART2, you must disable USB2 first. |
111 | */ | 111 | */ |
112 | void __init omap_serial_init(int ports[OMAP_MAX_NR_PORTS]) | 112 | void __init omap_serial_init(void) |
113 | { | 113 | { |
114 | int i; | 114 | int i; |
115 | const struct omap_uart_config *info; | ||
115 | 116 | ||
116 | if (cpu_is_omap730()) { | 117 | if (cpu_is_omap730()) { |
117 | serial_platform_data[0].regshift = 0; | 118 | serial_platform_data[0].regshift = 0; |
@@ -126,10 +127,14 @@ void __init omap_serial_init(int ports[OMAP_MAX_NR_PORTS]) | |||
126 | serial_platform_data[2].uartclk = OMAP1510_BASE_BAUD * 16; | 127 | serial_platform_data[2].uartclk = OMAP1510_BASE_BAUD * 16; |
127 | } | 128 | } |
128 | 129 | ||
130 | info = omap_get_config(OMAP_TAG_UART, struct omap_uart_config); | ||
131 | if (info == NULL) | ||
132 | return; | ||
133 | |||
129 | for (i = 0; i < OMAP_MAX_NR_PORTS; i++) { | 134 | for (i = 0; i < OMAP_MAX_NR_PORTS; i++) { |
130 | unsigned char reg; | 135 | unsigned char reg; |
131 | 136 | ||
132 | if (ports[i] == 0) { | 137 | if (!((1 << i) & info->enabled_uarts)) { |
133 | serial_platform_data[i].membase = NULL; | 138 | serial_platform_data[i].membase = NULL; |
134 | serial_platform_data[i].mapbase = 0; | 139 | serial_platform_data[i].mapbase = 0; |
135 | continue; | 140 | continue; |
diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c index 191a9b1ee9b7..cdbf4d7620c6 100644 --- a/arch/arm/mach-omap1/time.c +++ b/arch/arm/mach-omap1/time.c | |||
@@ -226,8 +226,8 @@ unsigned long long sched_clock(void) | |||
226 | 226 | ||
227 | #ifdef CONFIG_OMAP_32K_TIMER | 227 | #ifdef CONFIG_OMAP_32K_TIMER |
228 | 228 | ||
229 | #ifdef CONFIG_ARCH_OMAP1510 | 229 | #ifdef CONFIG_ARCH_OMAP15XX |
230 | #error OMAP 32KHz timer does not currently work on 1510! | 230 | #error OMAP 32KHz timer does not currently work on 15XX! |
231 | #endif | 231 | #endif |
232 | 232 | ||
233 | /* | 233 | /* |
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig new file mode 100644 index 000000000000..578880943cf2 --- /dev/null +++ b/arch/arm/mach-omap2/Kconfig | |||
@@ -0,0 +1,22 @@ | |||
1 | comment "OMAP Core Type" | ||
2 | depends on ARCH_OMAP2 | ||
3 | |||
4 | config ARCH_OMAP24XX | ||
5 | bool "OMAP24xx Based System" | ||
6 | depends on ARCH_OMAP2 | ||
7 | |||
8 | config ARCH_OMAP2420 | ||
9 | bool "OMAP2420 support" | ||
10 | depends on ARCH_OMAP24XX | ||
11 | |||
12 | comment "OMAP Board Type" | ||
13 | depends on ARCH_OMAP2 | ||
14 | |||
15 | config MACH_OMAP_GENERIC | ||
16 | bool "Generic OMAP board" | ||
17 | depends on ARCH_OMAP2 && ARCH_OMAP24XX | ||
18 | |||
19 | config MACH_OMAP_H4 | ||
20 | bool "OMAP 2420 H4 board" | ||
21 | depends on ARCH_OMAP2 && ARCH_OMAP24XX | ||
22 | |||
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile new file mode 100644 index 000000000000..42041166435c --- /dev/null +++ b/arch/arm/mach-omap2/Makefile | |||
@@ -0,0 +1,13 @@ | |||
1 | # | ||
2 | # Makefile for the linux kernel. | ||
3 | # | ||
4 | |||
5 | # Common support | ||
6 | obj-y := irq.o id.o io.o sram-fn.o clock.o mux.o devices.o serial.o | ||
7 | |||
8 | obj-$(CONFIG_OMAP_MPU_TIMER) += timer-gp.o | ||
9 | |||
10 | # Specific board support | ||
11 | obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o | ||
12 | obj-$(CONFIG_MACH_OMAP_H4) += board-h4.o | ||
13 | |||
diff --git a/arch/arm/mach-omap2/Makefile.boot b/arch/arm/mach-omap2/Makefile.boot new file mode 100644 index 000000000000..565aff7f37a9 --- /dev/null +++ b/arch/arm/mach-omap2/Makefile.boot | |||
@@ -0,0 +1,3 @@ | |||
1 | zreladdr-y := 0x80008000 | ||
2 | params_phys-y := 0x80000100 | ||
3 | initrd_phys-y := 0x80800000 | ||
diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c new file mode 100644 index 000000000000..c602e7a3d93e --- /dev/null +++ b/arch/arm/mach-omap2/board-generic.c | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-omap/omap2/board-generic.c | ||
3 | * | ||
4 | * Copyright (C) 2005 Nokia Corporation | ||
5 | * Author: Paul Mundt <paul.mundt@nokia.com> | ||
6 | * | ||
7 | * Modified from mach-omap/omap1/board-generic.c | ||
8 | * | ||
9 | * Code for generic OMAP2 board. Should work on many OMAP2 systems where | ||
10 | * the bootloader passes the board-specific data to the kernel. | ||
11 | * Do not put any board specific code to this file; create a new machine | ||
12 | * type if you need custom low-level initializations. | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License version 2 as | ||
16 | * published by the Free Software Foundation. | ||
17 | */ | ||
18 | |||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/device.h> | ||
22 | |||
23 | #include <asm/hardware.h> | ||
24 | #include <asm/mach-types.h> | ||
25 | #include <asm/mach/arch.h> | ||
26 | #include <asm/mach/map.h> | ||
27 | |||
28 | #include <asm/arch/gpio.h> | ||
29 | #include <asm/arch/mux.h> | ||
30 | #include <asm/arch/usb.h> | ||
31 | #include <asm/arch/board.h> | ||
32 | #include <asm/arch/common.h> | ||
33 | |||
34 | static void __init omap_generic_init_irq(void) | ||
35 | { | ||
36 | omap_init_irq(); | ||
37 | } | ||
38 | |||
39 | static struct omap_uart_config generic_uart_config __initdata = { | ||
40 | .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), | ||
41 | }; | ||
42 | |||
43 | static struct omap_mmc_config generic_mmc_config __initdata = { | ||
44 | .mmc [0] = { | ||
45 | .enabled = 0, | ||
46 | .wire4 = 0, | ||
47 | .wp_pin = -1, | ||
48 | .power_pin = -1, | ||
49 | .switch_pin = -1, | ||
50 | }, | ||
51 | }; | ||
52 | |||
53 | static struct omap_board_config_kernel generic_config[] = { | ||
54 | { OMAP_TAG_UART, &generic_uart_config }, | ||
55 | { OMAP_TAG_MMC, &generic_mmc_config }, | ||
56 | }; | ||
57 | |||
58 | static void __init omap_generic_init(void) | ||
59 | { | ||
60 | omap_board_config = generic_config; | ||
61 | omap_board_config_size = ARRAY_SIZE(generic_config); | ||
62 | omap_serial_init(); | ||
63 | } | ||
64 | |||
65 | static void __init omap_generic_map_io(void) | ||
66 | { | ||
67 | omap_map_common_io(); | ||
68 | } | ||
69 | |||
70 | MACHINE_START(OMAP_GENERIC, "Generic OMAP24xx") | ||
71 | /* Maintainer: Paul Mundt <paul.mundt@nokia.com> */ | ||
72 | .phys_ram = 0x80000000, | ||
73 | .phys_io = 0x48000000, | ||
74 | .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc, | ||
75 | .boot_params = 0x80000100, | ||
76 | .map_io = omap_generic_map_io, | ||
77 | .init_irq = omap_generic_init_irq, | ||
78 | .init_machine = omap_generic_init, | ||
79 | .timer = &omap_timer, | ||
80 | MACHINE_END | ||
diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c new file mode 100644 index 000000000000..f2554469a76a --- /dev/null +++ b/arch/arm/mach-omap2/board-h4.c | |||
@@ -0,0 +1,197 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-omap/omap2/board-h4.c | ||
3 | * | ||
4 | * Copyright (C) 2005 Nokia Corporation | ||
5 | * Author: Paul Mundt <paul.mundt@nokia.com> | ||
6 | * | ||
7 | * Modified from mach-omap/omap1/board-generic.c | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/mtd/mtd.h> | ||
18 | #include <linux/mtd/partitions.h> | ||
19 | #include <linux/delay.h> | ||
20 | |||
21 | #include <asm/hardware.h> | ||
22 | #include <asm/mach-types.h> | ||
23 | #include <asm/mach/arch.h> | ||
24 | #include <asm/mach/map.h> | ||
25 | #include <asm/mach/flash.h> | ||
26 | |||
27 | #include <asm/arch/gpio.h> | ||
28 | #include <asm/arch/mux.h> | ||
29 | #include <asm/arch/usb.h> | ||
30 | #include <asm/arch/board.h> | ||
31 | #include <asm/arch/common.h> | ||
32 | #include <asm/arch/prcm.h> | ||
33 | |||
34 | #include <asm/io.h> | ||
35 | #include <asm/delay.h> | ||
36 | |||
37 | static struct mtd_partition h4_partitions[] = { | ||
38 | /* bootloader (U-Boot, etc) in first sector */ | ||
39 | { | ||
40 | .name = "bootloader", | ||
41 | .offset = 0, | ||
42 | .size = SZ_128K, | ||
43 | .mask_flags = MTD_WRITEABLE, /* force read-only */ | ||
44 | }, | ||
45 | /* bootloader params in the next sector */ | ||
46 | { | ||
47 | .name = "params", | ||
48 | .offset = MTDPART_OFS_APPEND, | ||
49 | .size = SZ_128K, | ||
50 | .mask_flags = 0, | ||
51 | }, | ||
52 | /* kernel */ | ||
53 | { | ||
54 | .name = "kernel", | ||
55 | .offset = MTDPART_OFS_APPEND, | ||
56 | .size = SZ_2M, | ||
57 | .mask_flags = 0 | ||
58 | }, | ||
59 | /* file system */ | ||
60 | { | ||
61 | .name = "filesystem", | ||
62 | .offset = MTDPART_OFS_APPEND, | ||
63 | .size = MTDPART_SIZ_FULL, | ||
64 | .mask_flags = 0 | ||
65 | } | ||
66 | }; | ||
67 | |||
68 | static struct flash_platform_data h4_flash_data = { | ||
69 | .map_name = "cfi_probe", | ||
70 | .width = 2, | ||
71 | .parts = h4_partitions, | ||
72 | .nr_parts = ARRAY_SIZE(h4_partitions), | ||
73 | }; | ||
74 | |||
75 | static struct resource h4_flash_resource = { | ||
76 | .start = H4_CS0_BASE, | ||
77 | .end = H4_CS0_BASE + SZ_64M - 1, | ||
78 | .flags = IORESOURCE_MEM, | ||
79 | }; | ||
80 | |||
81 | static struct platform_device h4_flash_device = { | ||
82 | .name = "omapflash", | ||
83 | .id = 0, | ||
84 | .dev = { | ||
85 | .platform_data = &h4_flash_data, | ||
86 | }, | ||
87 | .num_resources = 1, | ||
88 | .resource = &h4_flash_resource, | ||
89 | }; | ||
90 | |||
91 | static struct resource h4_smc91x_resources[] = { | ||
92 | [0] = { | ||
93 | .start = OMAP24XX_ETHR_START, /* Physical */ | ||
94 | .end = OMAP24XX_ETHR_START + 0xf, | ||
95 | .flags = IORESOURCE_MEM, | ||
96 | }, | ||
97 | [1] = { | ||
98 | .start = OMAP_GPIO_IRQ(OMAP24XX_ETHR_GPIO_IRQ), | ||
99 | .end = OMAP_GPIO_IRQ(OMAP24XX_ETHR_GPIO_IRQ), | ||
100 | .flags = IORESOURCE_IRQ, | ||
101 | }, | ||
102 | }; | ||
103 | |||
104 | static struct platform_device h4_smc91x_device = { | ||
105 | .name = "smc91x", | ||
106 | .id = -1, | ||
107 | .num_resources = ARRAY_SIZE(h4_smc91x_resources), | ||
108 | .resource = h4_smc91x_resources, | ||
109 | }; | ||
110 | |||
111 | static struct platform_device *h4_devices[] __initdata = { | ||
112 | &h4_smc91x_device, | ||
113 | &h4_flash_device, | ||
114 | }; | ||
115 | |||
116 | static inline void __init h4_init_smc91x(void) | ||
117 | { | ||
118 | /* Make sure CS1 timings are correct */ | ||
119 | GPMC_CONFIG1_1 = 0x00011200; | ||
120 | GPMC_CONFIG2_1 = 0x001f1f01; | ||
121 | GPMC_CONFIG3_1 = 0x00080803; | ||
122 | GPMC_CONFIG4_1 = 0x1c091c09; | ||
123 | GPMC_CONFIG5_1 = 0x041f1f1f; | ||
124 | GPMC_CONFIG6_1 = 0x000004c4; | ||
125 | GPMC_CONFIG7_1 = 0x00000f40 | (0x08000000 >> 24); | ||
126 | udelay(100); | ||
127 | |||
128 | omap_cfg_reg(M15_24XX_GPIO92); | ||
129 | if (omap_request_gpio(OMAP24XX_ETHR_GPIO_IRQ) < 0) { | ||
130 | printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n", | ||
131 | OMAP24XX_ETHR_GPIO_IRQ); | ||
132 | return; | ||
133 | } | ||
134 | omap_set_gpio_direction(OMAP24XX_ETHR_GPIO_IRQ, 1); | ||
135 | } | ||
136 | |||
137 | static void __init omap_h4_init_irq(void) | ||
138 | { | ||
139 | omap_init_irq(); | ||
140 | omap_gpio_init(); | ||
141 | h4_init_smc91x(); | ||
142 | } | ||
143 | |||
144 | static struct omap_uart_config h4_uart_config __initdata = { | ||
145 | .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), | ||
146 | }; | ||
147 | |||
148 | static struct omap_mmc_config h4_mmc_config __initdata = { | ||
149 | .mmc [0] = { | ||
150 | .enabled = 1, | ||
151 | .wire4 = 1, | ||
152 | .wp_pin = -1, | ||
153 | .power_pin = -1, | ||
154 | .switch_pin = -1, | ||
155 | }, | ||
156 | }; | ||
157 | |||
158 | static struct omap_lcd_config h4_lcd_config __initdata = { | ||
159 | .panel_name = "h4", | ||
160 | .ctrl_name = "internal", | ||
161 | }; | ||
162 | |||
163 | static struct omap_board_config_kernel h4_config[] = { | ||
164 | { OMAP_TAG_UART, &h4_uart_config }, | ||
165 | { OMAP_TAG_MMC, &h4_mmc_config }, | ||
166 | { OMAP_TAG_LCD, &h4_lcd_config }, | ||
167 | }; | ||
168 | |||
169 | static void __init omap_h4_init(void) | ||
170 | { | ||
171 | /* | ||
172 | * Make sure the serial ports are muxed on at this point. | ||
173 | * You have to mux them off in device drivers later on | ||
174 | * if not needed. | ||
175 | */ | ||
176 | platform_add_devices(h4_devices, ARRAY_SIZE(h4_devices)); | ||
177 | omap_board_config = h4_config; | ||
178 | omap_board_config_size = ARRAY_SIZE(h4_config); | ||
179 | omap_serial_init(); | ||
180 | } | ||
181 | |||
182 | static void __init omap_h4_map_io(void) | ||
183 | { | ||
184 | omap_map_common_io(); | ||
185 | } | ||
186 | |||
187 | MACHINE_START(OMAP_H4, "OMAP2420 H4 board") | ||
188 | /* Maintainer: Paul Mundt <paul.mundt@nokia.com> */ | ||
189 | .phys_ram = 0x80000000, | ||
190 | .phys_io = 0x48000000, | ||
191 | .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc, | ||
192 | .boot_params = 0x80000100, | ||
193 | .map_io = omap_h4_map_io, | ||
194 | .init_irq = omap_h4_init_irq, | ||
195 | .init_machine = omap_h4_init, | ||
196 | .timer = &omap_timer, | ||
197 | MACHINE_END | ||
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c new file mode 100644 index 000000000000..85818d9f2635 --- /dev/null +++ b/arch/arm/mach-omap2/clock.c | |||
@@ -0,0 +1,1129 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-omap2/clock.c | ||
3 | * | ||
4 | * Copyright (C) 2005 Texas Instruments Inc. | ||
5 | * Richard Woodruff <r-woodruff2@ti.com> | ||
6 | * Created for OMAP2. | ||
7 | * | ||
8 | * Cleaned up and modified to use omap shared clock framework by | ||
9 | * Tony Lindgren <tony@atomide.com> | ||
10 | * | ||
11 | * Based on omap1 clock.c, Copyright (C) 2004 - 2005 Nokia corporation | ||
12 | * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License version 2 as | ||
16 | * published by the Free Software Foundation. | ||
17 | */ | ||
18 | #include <linux/config.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/device.h> | ||
22 | #include <linux/list.h> | ||
23 | #include <linux/errno.h> | ||
24 | #include <linux/delay.h> | ||
25 | |||
26 | #include <asm/io.h> | ||
27 | |||
28 | #include <asm/hardware/clock.h> | ||
29 | #include <asm/arch/clock.h> | ||
30 | #include <asm/arch/sram.h> | ||
31 | #include <asm/arch/prcm.h> | ||
32 | |||
33 | #include "clock.h" | ||
34 | |||
35 | //#define DOWN_VARIABLE_DPLL 1 /* Experimental */ | ||
36 | |||
37 | static struct prcm_config *curr_prcm_set; | ||
38 | static struct memory_timings mem_timings; | ||
39 | static u32 curr_perf_level = PRCM_FULL_SPEED; | ||
40 | |||
41 | /*------------------------------------------------------------------------- | ||
42 | * Omap2 specific clock functions | ||
43 | *-------------------------------------------------------------------------*/ | ||
44 | |||
45 | /* Recalculate SYST_CLK */ | ||
46 | static void omap2_sys_clk_recalc(struct clk * clk) | ||
47 | { | ||
48 | u32 div = PRCM_CLKSRC_CTRL; | ||
49 | div &= (1 << 7) | (1 << 6); /* Test if ext clk divided by 1 or 2 */ | ||
50 | div >>= clk->rate_offset; | ||
51 | clk->rate = (clk->parent->rate / div); | ||
52 | propagate_rate(clk); | ||
53 | } | ||
54 | |||
55 | static u32 omap2_get_dpll_rate(struct clk * tclk) | ||
56 | { | ||
57 | int dpll_clk, dpll_mult, dpll_div, amult; | ||
58 | |||
59 | dpll_mult = (CM_CLKSEL1_PLL >> 12) & 0x03ff; /* 10 bits */ | ||
60 | dpll_div = (CM_CLKSEL1_PLL >> 8) & 0x0f; /* 4 bits */ | ||
61 | dpll_clk = (tclk->parent->rate * dpll_mult) / (dpll_div + 1); | ||
62 | amult = CM_CLKSEL2_PLL & 0x3; | ||
63 | dpll_clk *= amult; | ||
64 | |||
65 | return dpll_clk; | ||
66 | } | ||
67 | |||
68 | static void omap2_followparent_recalc(struct clk *clk) | ||
69 | { | ||
70 | followparent_recalc(clk); | ||
71 | } | ||
72 | |||
73 | static void omap2_propagate_rate(struct clk * clk) | ||
74 | { | ||
75 | if (!(clk->flags & RATE_FIXED)) | ||
76 | clk->rate = clk->parent->rate; | ||
77 | |||
78 | propagate_rate(clk); | ||
79 | } | ||
80 | |||
81 | /* Enable an APLL if off */ | ||
82 | static void omap2_clk_fixed_enable(struct clk *clk) | ||
83 | { | ||
84 | u32 cval, i=0; | ||
85 | |||
86 | if (clk->enable_bit == 0xff) /* Parent will do it */ | ||
87 | return; | ||
88 | |||
89 | cval = CM_CLKEN_PLL; | ||
90 | |||
91 | if ((cval & (0x3 << clk->enable_bit)) == (0x3 << clk->enable_bit)) | ||
92 | return; | ||
93 | |||
94 | cval &= ~(0x3 << clk->enable_bit); | ||
95 | cval |= (0x3 << clk->enable_bit); | ||
96 | CM_CLKEN_PLL = cval; | ||
97 | |||
98 | if (clk == &apll96_ck) | ||
99 | cval = (1 << 8); | ||
100 | else if (clk == &apll54_ck) | ||
101 | cval = (1 << 6); | ||
102 | |||
103 | while (!CM_IDLEST_CKGEN & cval) { /* Wait for lock */ | ||
104 | ++i; | ||
105 | udelay(1); | ||
106 | if (i == 100000) | ||
107 | break; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | /* Enables clock without considering parent dependencies or use count | ||
112 | * REVISIT: Maybe change this to use clk->enable like on omap1? | ||
113 | */ | ||
114 | static int omap2_clk_enable(struct clk * clk) | ||
115 | { | ||
116 | u32 regval32; | ||
117 | |||
118 | if (clk->flags & ALWAYS_ENABLED) | ||
119 | return 0; | ||
120 | |||
121 | if (unlikely(clk->enable_reg == 0)) { | ||
122 | printk(KERN_ERR "clock.c: Enable for %s without enable code\n", | ||
123 | clk->name); | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | if (clk->enable_reg == (void __iomem *)&CM_CLKEN_PLL) { | ||
128 | omap2_clk_fixed_enable(clk); | ||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | regval32 = __raw_readl(clk->enable_reg); | ||
133 | regval32 |= (1 << clk->enable_bit); | ||
134 | __raw_writel(regval32, clk->enable_reg); | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | /* Stop APLL */ | ||
140 | static void omap2_clk_fixed_disable(struct clk *clk) | ||
141 | { | ||
142 | u32 cval; | ||
143 | |||
144 | if(clk->enable_bit == 0xff) /* let parent off do it */ | ||
145 | return; | ||
146 | |||
147 | cval = CM_CLKEN_PLL; | ||
148 | cval &= ~(0x3 << clk->enable_bit); | ||
149 | CM_CLKEN_PLL = cval; | ||
150 | } | ||
151 | |||
152 | /* Disables clock without considering parent dependencies or use count */ | ||
153 | static void omap2_clk_disable(struct clk *clk) | ||
154 | { | ||
155 | u32 regval32; | ||
156 | |||
157 | if (clk->enable_reg == 0) | ||
158 | return; | ||
159 | |||
160 | if (clk->enable_reg == (void __iomem *)&CM_CLKEN_PLL) { | ||
161 | omap2_clk_fixed_disable(clk); | ||
162 | return; | ||
163 | } | ||
164 | |||
165 | regval32 = __raw_readl(clk->enable_reg); | ||
166 | regval32 &= ~(1 << clk->enable_bit); | ||
167 | __raw_writel(regval32, clk->enable_reg); | ||
168 | } | ||
169 | |||
170 | static int omap2_clk_use(struct clk *clk) | ||
171 | { | ||
172 | int ret = 0; | ||
173 | |||
174 | if (clk->usecount++ == 0) { | ||
175 | if (likely((u32)clk->parent)) | ||
176 | ret = omap2_clk_use(clk->parent); | ||
177 | |||
178 | if (unlikely(ret != 0)) { | ||
179 | clk->usecount--; | ||
180 | return ret; | ||
181 | } | ||
182 | |||
183 | ret = omap2_clk_enable(clk); | ||
184 | |||
185 | if (unlikely(ret != 0) && clk->parent) { | ||
186 | omap2_clk_unuse(clk->parent); | ||
187 | clk->usecount--; | ||
188 | } | ||
189 | } | ||
190 | |||
191 | return ret; | ||
192 | } | ||
193 | |||
194 | static void omap2_clk_unuse(struct clk *clk) | ||
195 | { | ||
196 | if (clk->usecount > 0 && !(--clk->usecount)) { | ||
197 | omap2_clk_disable(clk); | ||
198 | if (likely((u32)clk->parent)) | ||
199 | omap2_clk_unuse(clk->parent); | ||
200 | } | ||
201 | } | ||
202 | |||
203 | /* | ||
204 | * Uses the current prcm set to tell if a rate is valid. | ||
205 | * You can go slower, but not faster within a given rate set. | ||
206 | */ | ||
207 | static u32 omap2_dpll_round_rate(unsigned long target_rate) | ||
208 | { | ||
209 | u32 high, low; | ||
210 | |||
211 | if ((CM_CLKSEL2_PLL & 0x3) == 1) { /* DPLL clockout */ | ||
212 | high = curr_prcm_set->dpll_speed * 2; | ||
213 | low = curr_prcm_set->dpll_speed; | ||
214 | } else { /* DPLL clockout x 2 */ | ||
215 | high = curr_prcm_set->dpll_speed; | ||
216 | low = curr_prcm_set->dpll_speed / 2; | ||
217 | } | ||
218 | |||
219 | #ifdef DOWN_VARIABLE_DPLL | ||
220 | if (target_rate > high) | ||
221 | return high; | ||
222 | else | ||
223 | return target_rate; | ||
224 | #else | ||
225 | if (target_rate > low) | ||
226 | return high; | ||
227 | else | ||
228 | return low; | ||
229 | #endif | ||
230 | |||
231 | } | ||
232 | |||
233 | /* | ||
234 | * Used for clocks that are part of CLKSEL_xyz governed clocks. | ||
235 | * REVISIT: Maybe change to use clk->enable() functions like on omap1? | ||
236 | */ | ||
237 | static void omap2_clksel_recalc(struct clk * clk) | ||
238 | { | ||
239 | u32 fixed = 0, div = 0; | ||
240 | |||
241 | if (clk == &dpll_ck) { | ||
242 | clk->rate = omap2_get_dpll_rate(clk); | ||
243 | fixed = 1; | ||
244 | div = 0; | ||
245 | } | ||
246 | |||
247 | if (clk == &iva1_mpu_int_ifck) { | ||
248 | div = 2; | ||
249 | fixed = 1; | ||
250 | } | ||
251 | |||
252 | if ((clk == &dss1_fck) && ((CM_CLKSEL1_CORE & (0x1f << 8)) == 0)) { | ||
253 | clk->rate = sys_ck.rate; | ||
254 | return; | ||
255 | } | ||
256 | |||
257 | if (!fixed) { | ||
258 | div = omap2_clksel_get_divisor(clk); | ||
259 | if (div == 0) | ||
260 | return; | ||
261 | } | ||
262 | |||
263 | if (div != 0) { | ||
264 | if (unlikely(clk->rate == clk->parent->rate / div)) | ||
265 | return; | ||
266 | clk->rate = clk->parent->rate / div; | ||
267 | } | ||
268 | |||
269 | if (unlikely(clk->flags & RATE_PROPAGATES)) | ||
270 | propagate_rate(clk); | ||
271 | } | ||
272 | |||
273 | /* | ||
274 | * Finds best divider value in an array based on the source and target | ||
275 | * rates. The divider array must be sorted with smallest divider first. | ||
276 | */ | ||
277 | static inline u32 omap2_divider_from_table(u32 size, u32 *div_array, | ||
278 | u32 src_rate, u32 tgt_rate) | ||
279 | { | ||
280 | int i, test_rate; | ||
281 | |||
282 | if (div_array == NULL) | ||
283 | return ~1; | ||
284 | |||
285 | for (i=0; i < size; i++) { | ||
286 | test_rate = src_rate / *div_array; | ||
287 | if (test_rate <= tgt_rate) | ||
288 | return *div_array; | ||
289 | ++div_array; | ||
290 | } | ||
291 | |||
292 | return ~0; /* No acceptable divider */ | ||
293 | } | ||
294 | |||
295 | /* | ||
296 | * Find divisor for the given clock and target rate. | ||
297 | * | ||
298 | * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT, | ||
299 | * they are only settable as part of virtual_prcm set. | ||
300 | */ | ||
301 | static u32 omap2_clksel_round_rate(struct clk *tclk, u32 target_rate, | ||
302 | u32 *new_div) | ||
303 | { | ||
304 | u32 gfx_div[] = {2, 3, 4}; | ||
305 | u32 sysclkout_div[] = {1, 2, 4, 8, 16}; | ||
306 | u32 dss1_div[] = {1, 2, 3, 4, 5, 6, 8, 9, 12, 16}; | ||
307 | u32 vylnq_div[] = {1, 2, 3, 4, 6, 8, 9, 12, 16, 18}; | ||
308 | u32 best_div = ~0, asize = 0; | ||
309 | u32 *div_array = NULL; | ||
310 | |||
311 | switch (tclk->flags & SRC_RATE_SEL_MASK) { | ||
312 | case CM_GFX_SEL1: | ||
313 | asize = 3; | ||
314 | div_array = gfx_div; | ||
315 | break; | ||
316 | case CM_PLL_SEL1: | ||
317 | return omap2_dpll_round_rate(target_rate); | ||
318 | case CM_SYSCLKOUT_SEL1: | ||
319 | asize = 5; | ||
320 | div_array = sysclkout_div; | ||
321 | break; | ||
322 | case CM_CORE_SEL1: | ||
323 | if(tclk == &dss1_fck){ | ||
324 | if(tclk->parent == &core_ck){ | ||
325 | asize = 10; | ||
326 | div_array = dss1_div; | ||
327 | } else { | ||
328 | *new_div = 0; /* fixed clk */ | ||
329 | return(tclk->parent->rate); | ||
330 | } | ||
331 | } else if((tclk == &vlynq_fck) && cpu_is_omap2420()){ | ||
332 | if(tclk->parent == &core_ck){ | ||
333 | asize = 10; | ||
334 | div_array = vylnq_div; | ||
335 | } else { | ||
336 | *new_div = 0; /* fixed clk */ | ||
337 | return(tclk->parent->rate); | ||
338 | } | ||
339 | } | ||
340 | break; | ||
341 | } | ||
342 | |||
343 | best_div = omap2_divider_from_table(asize, div_array, | ||
344 | tclk->parent->rate, target_rate); | ||
345 | if (best_div == ~0){ | ||
346 | *new_div = 1; | ||
347 | return best_div; /* signal error */ | ||
348 | } | ||
349 | |||
350 | *new_div = best_div; | ||
351 | return (tclk->parent->rate / best_div); | ||
352 | } | ||
353 | |||
354 | /* Given a clock and a rate apply a clock specific rounding function */ | ||
355 | static long omap2_clk_round_rate(struct clk *clk, unsigned long rate) | ||
356 | { | ||
357 | u32 new_div = 0; | ||
358 | int valid_rate; | ||
359 | |||
360 | if (clk->flags & RATE_FIXED) | ||
361 | return clk->rate; | ||
362 | |||
363 | if (clk->flags & RATE_CKCTL) { | ||
364 | valid_rate = omap2_clksel_round_rate(clk, rate, &new_div); | ||
365 | return valid_rate; | ||
366 | } | ||
367 | |||
368 | if (clk->round_rate != 0) | ||
369 | return clk->round_rate(clk, rate); | ||
370 | |||
371 | return clk->rate; | ||
372 | } | ||
373 | |||
374 | /* | ||
375 | * Check the DLL lock state, and return tue if running in unlock mode. | ||
376 | * This is needed to compenste for the shifted DLL value in unlock mode. | ||
377 | */ | ||
378 | static u32 omap2_dll_force_needed(void) | ||
379 | { | ||
380 | u32 dll_state = SDRC_DLLA_CTRL; /* dlla and dllb are a set */ | ||
381 | |||
382 | if ((dll_state & (1 << 2)) == (1 << 2)) | ||
383 | return 1; | ||
384 | else | ||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | static void omap2_init_memory_params(u32 force_lock_to_unlock_mode) | ||
389 | { | ||
390 | unsigned long dll_cnt; | ||
391 | u32 fast_dll = 0; | ||
392 | |||
393 | mem_timings.m_type = !((SDRC_MR_0 & 0x3) == 0x1); /* DDR = 1, SDR = 0 */ | ||
394 | |||
395 | /* 2422 es2.05 and beyond has a single SIP DDR instead of 2 like others. | ||
396 | * In the case of 2422, its ok to use CS1 instead of CS0. | ||
397 | */ | ||
398 | |||
399 | #if 0 /* FIXME: Enable after 24xx cpu detection works */ | ||
400 | ctype = get_cpu_type(); | ||
401 | if (cpu_is_omap2422()) | ||
402 | mem_timings.base_cs = 1; | ||
403 | else | ||
404 | #endif | ||
405 | mem_timings.base_cs = 0; | ||
406 | |||
407 | if (mem_timings.m_type != M_DDR) | ||
408 | return; | ||
409 | |||
410 | /* With DDR we need to determine the low frequency DLL value */ | ||
411 | if (((mem_timings.fast_dll_ctrl & (1 << 2)) == M_LOCK_CTRL)) | ||
412 | mem_timings.dll_mode = M_UNLOCK; | ||
413 | else | ||
414 | mem_timings.dll_mode = M_LOCK; | ||
415 | |||
416 | if (mem_timings.base_cs == 0) { | ||
417 | fast_dll = SDRC_DLLA_CTRL; | ||
418 | dll_cnt = SDRC_DLLA_STATUS & 0xff00; | ||
419 | } else { | ||
420 | fast_dll = SDRC_DLLB_CTRL; | ||
421 | dll_cnt = SDRC_DLLB_STATUS & 0xff00; | ||
422 | } | ||
423 | if (force_lock_to_unlock_mode) { | ||
424 | fast_dll &= ~0xff00; | ||
425 | fast_dll |= dll_cnt; /* Current lock mode */ | ||
426 | } | ||
427 | mem_timings.fast_dll_ctrl = fast_dll; | ||
428 | |||
429 | /* No disruptions, DDR will be offline & C-ABI not followed */ | ||
430 | omap2_sram_ddr_init(&mem_timings.slow_dll_ctrl, | ||
431 | mem_timings.fast_dll_ctrl, | ||
432 | mem_timings.base_cs, | ||
433 | force_lock_to_unlock_mode); | ||
434 | mem_timings.slow_dll_ctrl &= 0xff00; /* Keep lock value */ | ||
435 | |||
436 | /* Turn status into unlock ctrl */ | ||
437 | mem_timings.slow_dll_ctrl |= | ||
438 | ((mem_timings.fast_dll_ctrl & 0xF) | (1 << 2)); | ||
439 | |||
440 | /* 90 degree phase for anything below 133Mhz */ | ||
441 | mem_timings.slow_dll_ctrl |= (1 << 1); | ||
442 | } | ||
443 | |||
444 | static u32 omap2_reprogram_sdrc(u32 level, u32 force) | ||
445 | { | ||
446 | u32 prev = curr_perf_level, flags; | ||
447 | |||
448 | if ((curr_perf_level == level) && !force) | ||
449 | return prev; | ||
450 | |||
451 | if (level == PRCM_HALF_SPEED) { | ||
452 | local_irq_save(flags); | ||
453 | PRCM_VOLTSETUP = 0xffff; | ||
454 | omap2_sram_reprogram_sdrc(PRCM_HALF_SPEED, | ||
455 | mem_timings.slow_dll_ctrl, | ||
456 | mem_timings.m_type); | ||
457 | curr_perf_level = PRCM_HALF_SPEED; | ||
458 | local_irq_restore(flags); | ||
459 | } | ||
460 | if (level == PRCM_FULL_SPEED) { | ||
461 | local_irq_save(flags); | ||
462 | PRCM_VOLTSETUP = 0xffff; | ||
463 | omap2_sram_reprogram_sdrc(PRCM_FULL_SPEED, | ||
464 | mem_timings.fast_dll_ctrl, | ||
465 | mem_timings.m_type); | ||
466 | curr_perf_level = PRCM_FULL_SPEED; | ||
467 | local_irq_restore(flags); | ||
468 | } | ||
469 | |||
470 | return prev; | ||
471 | } | ||
472 | |||
473 | static int omap2_reprogram_dpll(struct clk * clk, unsigned long rate) | ||
474 | { | ||
475 | u32 flags, cur_rate, low, mult, div, valid_rate, done_rate; | ||
476 | u32 bypass = 0; | ||
477 | struct prcm_config tmpset; | ||
478 | int ret = -EINVAL; | ||
479 | |||
480 | local_irq_save(flags); | ||
481 | cur_rate = omap2_get_dpll_rate(&dpll_ck); | ||
482 | mult = CM_CLKSEL2_PLL & 0x3; | ||
483 | |||
484 | if ((rate == (cur_rate / 2)) && (mult == 2)) { | ||
485 | omap2_reprogram_sdrc(PRCM_HALF_SPEED, 1); | ||
486 | } else if ((rate == (cur_rate * 2)) && (mult == 1)) { | ||
487 | omap2_reprogram_sdrc(PRCM_FULL_SPEED, 1); | ||
488 | } else if (rate != cur_rate) { | ||
489 | valid_rate = omap2_dpll_round_rate(rate); | ||
490 | if (valid_rate != rate) | ||
491 | goto dpll_exit; | ||
492 | |||
493 | if ((CM_CLKSEL2_PLL & 0x3) == 1) | ||
494 | low = curr_prcm_set->dpll_speed; | ||
495 | else | ||
496 | low = curr_prcm_set->dpll_speed / 2; | ||
497 | |||
498 | tmpset.cm_clksel1_pll = CM_CLKSEL1_PLL; | ||
499 | tmpset.cm_clksel1_pll &= ~(0x3FFF << 8); | ||
500 | div = ((curr_prcm_set->xtal_speed / 1000000) - 1); | ||
501 | tmpset.cm_clksel2_pll = CM_CLKSEL2_PLL; | ||
502 | tmpset.cm_clksel2_pll &= ~0x3; | ||
503 | if (rate > low) { | ||
504 | tmpset.cm_clksel2_pll |= 0x2; | ||
505 | mult = ((rate / 2) / 1000000); | ||
506 | done_rate = PRCM_FULL_SPEED; | ||
507 | } else { | ||
508 | tmpset.cm_clksel2_pll |= 0x1; | ||
509 | mult = (rate / 1000000); | ||
510 | done_rate = PRCM_HALF_SPEED; | ||
511 | } | ||
512 | tmpset.cm_clksel1_pll |= ((div << 8) | (mult << 12)); | ||
513 | |||
514 | /* Worst case */ | ||
515 | tmpset.base_sdrc_rfr = V24XX_SDRC_RFR_CTRL_BYPASS; | ||
516 | |||
517 | if (rate == curr_prcm_set->xtal_speed) /* If asking for 1-1 */ | ||
518 | bypass = 1; | ||
519 | |||
520 | omap2_reprogram_sdrc(PRCM_FULL_SPEED, 1); /* For init_mem */ | ||
521 | |||
522 | /* Force dll lock mode */ | ||
523 | omap2_set_prcm(tmpset.cm_clksel1_pll, tmpset.base_sdrc_rfr, | ||
524 | bypass); | ||
525 | |||
526 | /* Errata: ret dll entry state */ | ||
527 | omap2_init_memory_params(omap2_dll_force_needed()); | ||
528 | omap2_reprogram_sdrc(done_rate, 0); | ||
529 | } | ||
530 | omap2_clksel_recalc(&dpll_ck); | ||
531 | ret = 0; | ||
532 | |||
533 | dpll_exit: | ||
534 | local_irq_restore(flags); | ||
535 | return(ret); | ||
536 | } | ||
537 | |||
538 | /* Just return the MPU speed */ | ||
539 | static void omap2_mpu_recalc(struct clk * clk) | ||
540 | { | ||
541 | clk->rate = curr_prcm_set->mpu_speed; | ||
542 | } | ||
543 | |||
544 | /* | ||
545 | * Look for a rate equal or less than the target rate given a configuration set. | ||
546 | * | ||
547 | * What's not entirely clear is "which" field represents the key field. | ||
548 | * Some might argue L3-DDR, others ARM, others IVA. This code is simple and | ||
549 | * just uses the ARM rates. | ||
550 | */ | ||
551 | static long omap2_round_to_table_rate(struct clk * clk, unsigned long rate) | ||
552 | { | ||
553 | struct prcm_config * ptr; | ||
554 | long highest_rate; | ||
555 | |||
556 | if (clk != &virt_prcm_set) | ||
557 | return -EINVAL; | ||
558 | |||
559 | highest_rate = -EINVAL; | ||
560 | |||
561 | for (ptr = rate_table; ptr->mpu_speed; ptr++) { | ||
562 | if (ptr->xtal_speed != sys_ck.rate) | ||
563 | continue; | ||
564 | |||
565 | highest_rate = ptr->mpu_speed; | ||
566 | |||
567 | /* Can check only after xtal frequency check */ | ||
568 | if (ptr->mpu_speed <= rate) | ||
569 | break; | ||
570 | } | ||
571 | return highest_rate; | ||
572 | } | ||
573 | |||
574 | /* | ||
575 | * omap2_convert_field_to_div() - turn field value into integer divider | ||
576 | */ | ||
577 | static u32 omap2_clksel_to_divisor(u32 div_sel, u32 field_val) | ||
578 | { | ||
579 | u32 i; | ||
580 | u32 clkout_array[] = {1, 2, 4, 8, 16}; | ||
581 | |||
582 | if ((div_sel & SRC_RATE_SEL_MASK) == CM_SYSCLKOUT_SEL1) { | ||
583 | for (i = 0; i < 5; i++) { | ||
584 | if (field_val == i) | ||
585 | return clkout_array[i]; | ||
586 | } | ||
587 | return ~0; | ||
588 | } else | ||
589 | return field_val; | ||
590 | } | ||
591 | |||
592 | /* | ||
593 | * Returns the CLKSEL divider register value | ||
594 | * REVISIT: This should be cleaned up to work nicely with void __iomem * | ||
595 | */ | ||
596 | static u32 omap2_get_clksel(u32 *div_sel, u32 *field_mask, | ||
597 | struct clk *clk) | ||
598 | { | ||
599 | int ret = ~0; | ||
600 | u32 reg_val, div_off; | ||
601 | u32 div_addr = 0; | ||
602 | u32 mask = ~0; | ||
603 | |||
604 | div_off = clk->rate_offset; | ||
605 | |||
606 | switch ((*div_sel & SRC_RATE_SEL_MASK)) { | ||
607 | case CM_MPU_SEL1: | ||
608 | div_addr = (u32)&CM_CLKSEL_MPU; | ||
609 | mask = 0x1f; | ||
610 | break; | ||
611 | case CM_DSP_SEL1: | ||
612 | div_addr = (u32)&CM_CLKSEL_DSP; | ||
613 | if (cpu_is_omap2420()) { | ||
614 | if ((div_off == 0) || (div_off == 8)) | ||
615 | mask = 0x1f; | ||
616 | else if (div_off == 5) | ||
617 | mask = 0x3; | ||
618 | } else if (cpu_is_omap2430()) { | ||
619 | if (div_off == 0) | ||
620 | mask = 0x1f; | ||
621 | else if (div_off == 5) | ||
622 | mask = 0x3; | ||
623 | } | ||
624 | break; | ||
625 | case CM_GFX_SEL1: | ||
626 | div_addr = (u32)&CM_CLKSEL_GFX; | ||
627 | if (div_off == 0) | ||
628 | mask = 0x7; | ||
629 | break; | ||
630 | case CM_MODEM_SEL1: | ||
631 | div_addr = (u32)&CM_CLKSEL_MDM; | ||
632 | if (div_off == 0) | ||
633 | mask = 0xf; | ||
634 | break; | ||
635 | case CM_SYSCLKOUT_SEL1: | ||
636 | div_addr = (u32)&PRCM_CLKOUT_CTRL; | ||
637 | if ((div_off == 3) || (div_off = 11)) | ||
638 | mask= 0x3; | ||
639 | break; | ||
640 | case CM_CORE_SEL1: | ||
641 | div_addr = (u32)&CM_CLKSEL1_CORE; | ||
642 | switch (div_off) { | ||
643 | case 0: /* l3 */ | ||
644 | case 8: /* dss1 */ | ||
645 | case 15: /* vylnc-2420 */ | ||
646 | case 20: /* ssi */ | ||
647 | mask = 0x1f; break; | ||
648 | case 5: /* l4 */ | ||
649 | mask = 0x3; break; | ||
650 | case 13: /* dss2 */ | ||
651 | mask = 0x1; break; | ||
652 | case 25: /* usb */ | ||
653 | mask = 0xf; break; | ||
654 | } | ||
655 | } | ||
656 | |||
657 | *field_mask = mask; | ||
658 | |||
659 | if (unlikely(mask == ~0)) | ||
660 | div_addr = 0; | ||
661 | |||
662 | *div_sel = div_addr; | ||
663 | |||
664 | if (unlikely(div_addr == 0)) | ||
665 | return ret; | ||
666 | |||
667 | /* Isolate field */ | ||
668 | reg_val = __raw_readl((void __iomem *)div_addr) & (mask << div_off); | ||
669 | |||
670 | /* Normalize back to divider value */ | ||
671 | reg_val >>= div_off; | ||
672 | |||
673 | return reg_val; | ||
674 | } | ||
675 | |||
676 | /* | ||
677 | * Return divider to be applied to parent clock. | ||
678 | * Return 0 on error. | ||
679 | */ | ||
680 | static u32 omap2_clksel_get_divisor(struct clk *clk) | ||
681 | { | ||
682 | int ret = 0; | ||
683 | u32 div, div_sel, div_off, field_mask, field_val; | ||
684 | |||
685 | /* isolate control register */ | ||
686 | div_sel = (SRC_RATE_SEL_MASK & clk->flags); | ||
687 | |||
688 | div_off = clk->rate_offset; | ||
689 | field_val = omap2_get_clksel(&div_sel, &field_mask, clk); | ||
690 | if (div_sel == 0) | ||
691 | return ret; | ||
692 | |||
693 | div_sel = (SRC_RATE_SEL_MASK & clk->flags); | ||
694 | div = omap2_clksel_to_divisor(div_sel, field_val); | ||
695 | |||
696 | return div; | ||
697 | } | ||
698 | |||
699 | /* Set the clock rate for a clock source */ | ||
700 | static int omap2_clk_set_rate(struct clk *clk, unsigned long rate) | ||
701 | |||
702 | { | ||
703 | int ret = -EINVAL; | ||
704 | void __iomem * reg; | ||
705 | u32 div_sel, div_off, field_mask, field_val, reg_val, validrate; | ||
706 | u32 new_div = 0; | ||
707 | |||
708 | if (!(clk->flags & CONFIG_PARTICIPANT) && (clk->flags & RATE_CKCTL)) { | ||
709 | if (clk == &dpll_ck) | ||
710 | return omap2_reprogram_dpll(clk, rate); | ||
711 | |||
712 | /* Isolate control register */ | ||
713 | div_sel = (SRC_RATE_SEL_MASK & clk->flags); | ||
714 | div_off = clk->src_offset; | ||
715 | |||
716 | validrate = omap2_clksel_round_rate(clk, rate, &new_div); | ||
717 | if(validrate != rate) | ||
718 | return(ret); | ||
719 | |||
720 | field_val = omap2_get_clksel(&div_sel, &field_mask, clk); | ||
721 | if (div_sel == 0) | ||
722 | return ret; | ||
723 | |||
724 | if(clk->flags & CM_SYSCLKOUT_SEL1){ | ||
725 | switch(new_div){ | ||
726 | case 16: field_val = 4; break; | ||
727 | case 8: field_val = 3; break; | ||
728 | case 4: field_val = 2; break; | ||
729 | case 2: field_val = 1; break; | ||
730 | case 1: field_val = 0; break; | ||
731 | } | ||
732 | } | ||
733 | else | ||
734 | field_val = new_div; | ||
735 | |||
736 | reg = (void __iomem *)div_sel; | ||
737 | |||
738 | reg_val = __raw_readl(reg); | ||
739 | reg_val &= ~(field_mask << div_off); | ||
740 | reg_val |= (field_val << div_off); | ||
741 | |||
742 | __raw_writel(reg_val, reg); | ||
743 | clk->rate = clk->parent->rate / field_val; | ||
744 | |||
745 | if (clk->flags & DELAYED_APP) | ||
746 | __raw_writel(0x1, (void __iomem *)&PRCM_CLKCFG_CTRL); | ||
747 | ret = 0; | ||
748 | } else if (clk->set_rate != 0) | ||
749 | ret = clk->set_rate(clk, rate); | ||
750 | |||
751 | if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES))) | ||
752 | propagate_rate(clk); | ||
753 | |||
754 | return ret; | ||
755 | } | ||
756 | |||
757 | /* Converts encoded control register address into a full address */ | ||
758 | static u32 omap2_get_src_field(u32 *type_to_addr, u32 reg_offset, | ||
759 | struct clk *src_clk, u32 *field_mask) | ||
760 | { | ||
761 | u32 val = ~0, src_reg_addr = 0, mask = 0; | ||
762 | |||
763 | /* Find target control register.*/ | ||
764 | switch ((*type_to_addr & SRC_RATE_SEL_MASK)) { | ||
765 | case CM_CORE_SEL1: | ||
766 | src_reg_addr = (u32)&CM_CLKSEL1_CORE; | ||
767 | if (reg_offset == 13) { /* DSS2_fclk */ | ||
768 | mask = 0x1; | ||
769 | if (src_clk == &sys_ck) | ||
770 | val = 0; | ||
771 | if (src_clk == &func_48m_ck) | ||
772 | val = 1; | ||
773 | } else if (reg_offset == 8) { /* DSS1_fclk */ | ||
774 | mask = 0x1f; | ||
775 | if (src_clk == &sys_ck) | ||
776 | val = 0; | ||
777 | else if (src_clk == &core_ck) /* divided clock */ | ||
778 | val = 0x10; /* rate needs fixing */ | ||
779 | } else if ((reg_offset == 15) && cpu_is_omap2420()){ /*vlnyq*/ | ||
780 | mask = 0x1F; | ||
781 | if(src_clk == &func_96m_ck) | ||
782 | val = 0; | ||
783 | else if (src_clk == &core_ck) | ||
784 | val = 0x10; | ||
785 | } | ||
786 | break; | ||
787 | case CM_CORE_SEL2: | ||
788 | src_reg_addr = (u32)&CM_CLKSEL2_CORE; | ||
789 | mask = 0x3; | ||
790 | if (src_clk == &func_32k_ck) | ||
791 | val = 0x0; | ||
792 | if (src_clk == &sys_ck) | ||
793 | val = 0x1; | ||
794 | if (src_clk == &alt_ck) | ||
795 | val = 0x2; | ||
796 | break; | ||
797 | case CM_WKUP_SEL1: | ||
798 | src_reg_addr = (u32)&CM_CLKSEL2_CORE; | ||
799 | mask = 0x3; | ||
800 | if (src_clk == &func_32k_ck) | ||
801 | val = 0x0; | ||
802 | if (src_clk == &sys_ck) | ||
803 | val = 0x1; | ||
804 | if (src_clk == &alt_ck) | ||
805 | val = 0x2; | ||
806 | break; | ||
807 | case CM_PLL_SEL1: | ||
808 | src_reg_addr = (u32)&CM_CLKSEL1_PLL; | ||
809 | mask = 0x1; | ||
810 | if (reg_offset == 0x3) { | ||
811 | if (src_clk == &apll96_ck) | ||
812 | val = 0; | ||
813 | if (src_clk == &alt_ck) | ||
814 | val = 1; | ||
815 | } | ||
816 | else if (reg_offset == 0x5) { | ||
817 | if (src_clk == &apll54_ck) | ||
818 | val = 0; | ||
819 | if (src_clk == &alt_ck) | ||
820 | val = 1; | ||
821 | } | ||
822 | break; | ||
823 | case CM_PLL_SEL2: | ||
824 | src_reg_addr = (u32)&CM_CLKSEL2_PLL; | ||
825 | mask = 0x3; | ||
826 | if (src_clk == &func_32k_ck) | ||
827 | val = 0x0; | ||
828 | if (src_clk == &dpll_ck) | ||
829 | val = 0x2; | ||
830 | break; | ||
831 | case CM_SYSCLKOUT_SEL1: | ||
832 | src_reg_addr = (u32)&PRCM_CLKOUT_CTRL; | ||
833 | mask = 0x3; | ||
834 | if (src_clk == &dpll_ck) | ||
835 | val = 0; | ||
836 | if (src_clk == &sys_ck) | ||
837 | val = 1; | ||
838 | if (src_clk == &func_54m_ck) | ||
839 | val = 2; | ||
840 | if (src_clk == &func_96m_ck) | ||
841 | val = 3; | ||
842 | break; | ||
843 | } | ||
844 | |||
845 | if (val == ~0) /* Catch errors in offset */ | ||
846 | *type_to_addr = 0; | ||
847 | else | ||
848 | *type_to_addr = src_reg_addr; | ||
849 | *field_mask = mask; | ||
850 | |||
851 | return val; | ||
852 | } | ||
853 | |||
854 | static int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent) | ||
855 | { | ||
856 | void __iomem * reg; | ||
857 | u32 src_sel, src_off, field_val, field_mask, reg_val, rate; | ||
858 | int ret = -EINVAL; | ||
859 | |||
860 | if (unlikely(clk->flags & CONFIG_PARTICIPANT)) | ||
861 | return ret; | ||
862 | |||
863 | if (clk->flags & SRC_SEL_MASK) { /* On-chip SEL collection */ | ||
864 | src_sel = (SRC_RATE_SEL_MASK & clk->flags); | ||
865 | src_off = clk->src_offset; | ||
866 | |||
867 | if (src_sel == 0) | ||
868 | goto set_parent_error; | ||
869 | |||
870 | field_val = omap2_get_src_field(&src_sel, src_off, new_parent, | ||
871 | &field_mask); | ||
872 | |||
873 | reg = (void __iomem *)src_sel; | ||
874 | |||
875 | if (clk->usecount > 0) | ||
876 | omap2_clk_disable(clk); | ||
877 | |||
878 | /* Set new source value (previous dividers if any in effect) */ | ||
879 | reg_val = __raw_readl(reg) & ~(field_mask << src_off); | ||
880 | reg_val |= (field_val << src_off); | ||
881 | __raw_writel(reg_val, reg); | ||
882 | |||
883 | if (clk->flags & DELAYED_APP) | ||
884 | __raw_writel(0x1, (void __iomem *)&PRCM_CLKCFG_CTRL); | ||
885 | |||
886 | if (clk->usecount > 0) | ||
887 | omap2_clk_enable(clk); | ||
888 | |||
889 | clk->parent = new_parent; | ||
890 | |||
891 | /* SRC_RATE_SEL_MASK clocks follow their parents rates.*/ | ||
892 | if ((new_parent == &core_ck) && (clk == &dss1_fck)) | ||
893 | clk->rate = new_parent->rate / 0x10; | ||
894 | else | ||
895 | clk->rate = new_parent->rate; | ||
896 | |||
897 | if (unlikely(clk->flags & RATE_PROPAGATES)) | ||
898 | propagate_rate(clk); | ||
899 | |||
900 | return 0; | ||
901 | } else { | ||
902 | clk->parent = new_parent; | ||
903 | rate = new_parent->rate; | ||
904 | omap2_clk_set_rate(clk, rate); | ||
905 | ret = 0; | ||
906 | } | ||
907 | |||
908 | set_parent_error: | ||
909 | return ret; | ||
910 | } | ||
911 | |||
912 | /* Sets basic clocks based on the specified rate */ | ||
913 | static int omap2_select_table_rate(struct clk * clk, unsigned long rate) | ||
914 | { | ||
915 | u32 flags, cur_rate, done_rate, bypass = 0; | ||
916 | u8 cpu_mask = 0; | ||
917 | struct prcm_config *prcm; | ||
918 | unsigned long found_speed = 0; | ||
919 | |||
920 | if (clk != &virt_prcm_set) | ||
921 | return -EINVAL; | ||
922 | |||
923 | /* FIXME: Change cpu_is_omap2420() to cpu_is_omap242x() */ | ||
924 | if (cpu_is_omap2420()) | ||
925 | cpu_mask = RATE_IN_242X; | ||
926 | else if (cpu_is_omap2430()) | ||
927 | cpu_mask = RATE_IN_243X; | ||
928 | |||
929 | for (prcm = rate_table; prcm->mpu_speed; prcm++) { | ||
930 | if (!(prcm->flags & cpu_mask)) | ||
931 | continue; | ||
932 | |||
933 | if (prcm->xtal_speed != sys_ck.rate) | ||
934 | continue; | ||
935 | |||
936 | if (prcm->mpu_speed <= rate) { | ||
937 | found_speed = prcm->mpu_speed; | ||
938 | break; | ||
939 | } | ||
940 | } | ||
941 | |||
942 | if (!found_speed) { | ||
943 | printk(KERN_INFO "Could not set MPU rate to %luMHz\n", | ||
944 | rate / 1000000); | ||
945 | return -EINVAL; | ||
946 | } | ||
947 | |||
948 | curr_prcm_set = prcm; | ||
949 | cur_rate = omap2_get_dpll_rate(&dpll_ck); | ||
950 | |||
951 | if (prcm->dpll_speed == cur_rate / 2) { | ||
952 | omap2_reprogram_sdrc(PRCM_HALF_SPEED, 1); | ||
953 | } else if (prcm->dpll_speed == cur_rate * 2) { | ||
954 | omap2_reprogram_sdrc(PRCM_FULL_SPEED, 1); | ||
955 | } else if (prcm->dpll_speed != cur_rate) { | ||
956 | local_irq_save(flags); | ||
957 | |||
958 | if (prcm->dpll_speed == prcm->xtal_speed) | ||
959 | bypass = 1; | ||
960 | |||
961 | if ((prcm->cm_clksel2_pll & 0x3) == 2) | ||
962 | done_rate = PRCM_FULL_SPEED; | ||
963 | else | ||
964 | done_rate = PRCM_HALF_SPEED; | ||
965 | |||
966 | /* MPU divider */ | ||
967 | CM_CLKSEL_MPU = prcm->cm_clksel_mpu; | ||
968 | |||
969 | /* dsp + iva1 div(2420), iva2.1(2430) */ | ||
970 | CM_CLKSEL_DSP = prcm->cm_clksel_dsp; | ||
971 | |||
972 | CM_CLKSEL_GFX = prcm->cm_clksel_gfx; | ||
973 | |||
974 | /* Major subsystem dividers */ | ||
975 | CM_CLKSEL1_CORE = prcm->cm_clksel1_core; | ||
976 | if (cpu_is_omap2430()) | ||
977 | CM_CLKSEL_MDM = prcm->cm_clksel_mdm; | ||
978 | |||
979 | /* x2 to enter init_mem */ | ||
980 | omap2_reprogram_sdrc(PRCM_FULL_SPEED, 1); | ||
981 | |||
982 | omap2_set_prcm(prcm->cm_clksel1_pll, prcm->base_sdrc_rfr, | ||
983 | bypass); | ||
984 | |||
985 | omap2_init_memory_params(omap2_dll_force_needed()); | ||
986 | omap2_reprogram_sdrc(done_rate, 0); | ||
987 | |||
988 | local_irq_restore(flags); | ||
989 | } | ||
990 | omap2_clksel_recalc(&dpll_ck); | ||
991 | |||
992 | return 0; | ||
993 | } | ||
994 | |||
995 | /*------------------------------------------------------------------------- | ||
996 | * Omap2 clock reset and init functions | ||
997 | *-------------------------------------------------------------------------*/ | ||
998 | |||
999 | static struct clk_functions omap2_clk_functions = { | ||
1000 | .clk_enable = omap2_clk_enable, | ||
1001 | .clk_disable = omap2_clk_disable, | ||
1002 | .clk_use = omap2_clk_use, | ||
1003 | .clk_unuse = omap2_clk_unuse, | ||
1004 | .clk_round_rate = omap2_clk_round_rate, | ||
1005 | .clk_set_rate = omap2_clk_set_rate, | ||
1006 | .clk_set_parent = omap2_clk_set_parent, | ||
1007 | }; | ||
1008 | |||
1009 | static void __init omap2_get_crystal_rate(struct clk *osc, struct clk *sys) | ||
1010 | { | ||
1011 | u32 div, aplls, sclk = 13000000; | ||
1012 | |||
1013 | aplls = CM_CLKSEL1_PLL; | ||
1014 | aplls &= ((1 << 23) | (1 << 24) | (1 << 25)); | ||
1015 | aplls >>= 23; /* Isolate field, 0,2,3 */ | ||
1016 | |||
1017 | if (aplls == 0) | ||
1018 | sclk = 19200000; | ||
1019 | else if (aplls == 2) | ||
1020 | sclk = 13000000; | ||
1021 | else if (aplls == 3) | ||
1022 | sclk = 12000000; | ||
1023 | |||
1024 | div = PRCM_CLKSRC_CTRL; | ||
1025 | div &= ((1 << 7) | (1 << 6)); | ||
1026 | div >>= sys->rate_offset; | ||
1027 | |||
1028 | osc->rate = sclk * div; | ||
1029 | sys->rate = sclk; | ||
1030 | } | ||
1031 | |||
1032 | #ifdef CONFIG_OMAP_RESET_CLOCKS | ||
1033 | static void __init omap2_disable_unused_clocks(void) | ||
1034 | { | ||
1035 | struct clk *ck; | ||
1036 | u32 regval32; | ||
1037 | |||
1038 | list_for_each_entry(ck, &clocks, node) { | ||
1039 | if (ck->usecount > 0 || (ck->flags & ALWAYS_ENABLED) || | ||
1040 | ck->enable_reg == 0) | ||
1041 | continue; | ||
1042 | |||
1043 | regval32 = __raw_readl(ck->enable_reg); | ||
1044 | if ((regval32 & (1 << ck->enable_bit)) == 0) | ||
1045 | continue; | ||
1046 | |||
1047 | printk(KERN_INFO "Disabling unused clock \"%s\"\n", ck->name); | ||
1048 | omap2_clk_disable(ck); | ||
1049 | } | ||
1050 | } | ||
1051 | late_initcall(omap2_disable_unused_clocks); | ||
1052 | #endif | ||
1053 | |||
1054 | /* | ||
1055 | * Switch the MPU rate if specified on cmdline. | ||
1056 | * We cannot do this early until cmdline is parsed. | ||
1057 | */ | ||
1058 | static int __init omap2_clk_arch_init(void) | ||
1059 | { | ||
1060 | if (!mpurate) | ||
1061 | return -EINVAL; | ||
1062 | |||
1063 | if (omap2_select_table_rate(&virt_prcm_set, mpurate)) | ||
1064 | printk(KERN_ERR "Could not find matching MPU rate\n"); | ||
1065 | |||
1066 | propagate_rate(&osc_ck); /* update main root fast */ | ||
1067 | propagate_rate(&func_32k_ck); /* update main root slow */ | ||
1068 | |||
1069 | printk(KERN_INFO "Switched to new clocking rate (Crystal/DPLL/MPU): " | ||
1070 | "%ld.%01ld/%ld/%ld MHz\n", | ||
1071 | (sys_ck.rate / 1000000), (sys_ck.rate / 100000) % 10, | ||
1072 | (dpll_ck.rate / 1000000), (mpu_ck.rate / 1000000)) ; | ||
1073 | |||
1074 | return 0; | ||
1075 | } | ||
1076 | arch_initcall(omap2_clk_arch_init); | ||
1077 | |||
1078 | int __init omap2_clk_init(void) | ||
1079 | { | ||
1080 | struct prcm_config *prcm; | ||
1081 | struct clk ** clkp; | ||
1082 | u32 clkrate; | ||
1083 | |||
1084 | clk_init(&omap2_clk_functions); | ||
1085 | omap2_get_crystal_rate(&osc_ck, &sys_ck); | ||
1086 | |||
1087 | for (clkp = onchip_clks; clkp < onchip_clks + ARRAY_SIZE(onchip_clks); | ||
1088 | clkp++) { | ||
1089 | |||
1090 | if ((*clkp)->flags & CLOCK_IN_OMAP242X && cpu_is_omap2420()) { | ||
1091 | clk_register(*clkp); | ||
1092 | continue; | ||
1093 | } | ||
1094 | |||
1095 | if ((*clkp)->flags & CLOCK_IN_OMAP243X && cpu_is_omap2430()) { | ||
1096 | clk_register(*clkp); | ||
1097 | continue; | ||
1098 | } | ||
1099 | } | ||
1100 | |||
1101 | /* Check the MPU rate set by bootloader */ | ||
1102 | clkrate = omap2_get_dpll_rate(&dpll_ck); | ||
1103 | for (prcm = rate_table; prcm->mpu_speed; prcm++) { | ||
1104 | if (prcm->xtal_speed != sys_ck.rate) | ||
1105 | continue; | ||
1106 | if (prcm->dpll_speed <= clkrate) | ||
1107 | break; | ||
1108 | } | ||
1109 | curr_prcm_set = prcm; | ||
1110 | |||
1111 | propagate_rate(&osc_ck); /* update main root fast */ | ||
1112 | propagate_rate(&func_32k_ck); /* update main root slow */ | ||
1113 | |||
1114 | printk(KERN_INFO "Clocking rate (Crystal/DPLL/MPU): " | ||
1115 | "%ld.%01ld/%ld/%ld MHz\n", | ||
1116 | (sys_ck.rate / 1000000), (sys_ck.rate / 100000) % 10, | ||
1117 | (dpll_ck.rate / 1000000), (mpu_ck.rate / 1000000)) ; | ||
1118 | |||
1119 | /* | ||
1120 | * Only enable those clocks we will need, let the drivers | ||
1121 | * enable other clocks as necessary | ||
1122 | */ | ||
1123 | clk_use(&sync_32k_ick); | ||
1124 | clk_use(&omapctrl_ick); | ||
1125 | if (cpu_is_omap2430()) | ||
1126 | clk_use(&sdrc_ick); | ||
1127 | |||
1128 | return 0; | ||
1129 | } | ||
diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h new file mode 100644 index 000000000000..4aeab5591bd3 --- /dev/null +++ b/arch/arm/mach-omap2/clock.h | |||
@@ -0,0 +1,2103 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-omap24xx/clock.h | ||
3 | * | ||
4 | * Copyright (C) 2005 Texas Instruments Inc. | ||
5 | * Richard Woodruff <r-woodruff2@ti.com> | ||
6 | * Created for OMAP2. | ||
7 | * | ||
8 | * Copyright (C) 2004 Nokia corporation | ||
9 | * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> | ||
10 | * Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, Inc | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | */ | ||
16 | |||
17 | #ifndef __ARCH_ARM_MACH_OMAP2_CLOCK_H | ||
18 | #define __ARCH_ARM_MACH_OMAP2_CLOCK_H | ||
19 | |||
20 | static void omap2_sys_clk_recalc(struct clk * clk); | ||
21 | static void omap2_clksel_recalc(struct clk * clk); | ||
22 | static void omap2_followparent_recalc(struct clk * clk); | ||
23 | static void omap2_propagate_rate(struct clk * clk); | ||
24 | static void omap2_mpu_recalc(struct clk * clk); | ||
25 | static int omap2_select_table_rate(struct clk * clk, unsigned long rate); | ||
26 | static long omap2_round_to_table_rate(struct clk * clk, unsigned long rate); | ||
27 | static void omap2_clk_unuse(struct clk *clk); | ||
28 | static void omap2_sys_clk_recalc(struct clk * clk); | ||
29 | static u32 omap2_clksel_to_divisor(u32 div_sel, u32 field_val); | ||
30 | static u32 omap2_clksel_get_divisor(struct clk *clk); | ||
31 | |||
32 | |||
33 | #define RATE_IN_242X (1 << 0) | ||
34 | #define RATE_IN_243X (1 << 1) | ||
35 | |||
36 | /* Memory timings */ | ||
37 | #define M_DDR 1 | ||
38 | #define M_LOCK_CTRL (1 << 2) | ||
39 | #define M_UNLOCK 0 | ||
40 | #define M_LOCK 1 | ||
41 | |||
42 | struct memory_timings { | ||
43 | u32 m_type; /* ddr = 1, sdr = 0 */ | ||
44 | u32 dll_mode; /* use lock mode = 1, unlock mode = 0 */ | ||
45 | u32 slow_dll_ctrl; /* unlock mode, dll value for slow speed */ | ||
46 | u32 fast_dll_ctrl; /* unlock mode, dll value for fast speed */ | ||
47 | u32 base_cs; /* base chip select to use for calculations */ | ||
48 | }; | ||
49 | |||
50 | /* Key dividers which make up a PRCM set. Ratio's for a PRCM are mandated. | ||
51 | * xtal_speed, dpll_speed, mpu_speed, CM_CLKSEL_MPU,CM_CLKSEL_DSP | ||
52 | * CM_CLKSEL_GFX, CM_CLKSEL1_CORE, CM_CLKSEL1_PLL CM_CLKSEL2_PLL, CM_CLKSEL_MDM | ||
53 | */ | ||
54 | struct prcm_config { | ||
55 | unsigned long xtal_speed; /* crystal rate */ | ||
56 | unsigned long dpll_speed; /* dpll: out*xtal*M/(N-1)table_recalc */ | ||
57 | unsigned long mpu_speed; /* speed of MPU */ | ||
58 | unsigned long cm_clksel_mpu; /* mpu divider */ | ||
59 | unsigned long cm_clksel_dsp; /* dsp+iva1 div(2420), iva2.1(2430) */ | ||
60 | unsigned long cm_clksel_gfx; /* gfx dividers */ | ||
61 | unsigned long cm_clksel1_core; /* major subsystem dividers */ | ||
62 | unsigned long cm_clksel1_pll; /* m,n */ | ||
63 | unsigned long cm_clksel2_pll; /* dpllx1 or x2 out */ | ||
64 | unsigned long cm_clksel_mdm; /* modem dividers 2430 only */ | ||
65 | unsigned long base_sdrc_rfr; /* base refresh timing for a set */ | ||
66 | unsigned char flags; | ||
67 | }; | ||
68 | |||
69 | /* Mask for clksel which support parent settign in set_rate */ | ||
70 | #define SRC_SEL_MASK (CM_CORE_SEL1 | CM_CORE_SEL2 | CM_WKUP_SEL1 | \ | ||
71 | CM_PLL_SEL1 | CM_PLL_SEL2 | CM_SYSCLKOUT_SEL1) | ||
72 | |||
73 | /* Mask for clksel regs which support rate operations */ | ||
74 | #define SRC_RATE_SEL_MASK (CM_MPU_SEL1 | CM_DSP_SEL1 | CM_GFX_SEL1 | \ | ||
75 | CM_MODEM_SEL1 | CM_CORE_SEL1 | CM_CORE_SEL2 | \ | ||
76 | CM_WKUP_SEL1 | CM_PLL_SEL1 | CM_PLL_SEL2 | \ | ||
77 | CM_SYSCLKOUT_SEL1) | ||
78 | |||
79 | /* | ||
80 | * The OMAP2 processor can be run at several discrete 'PRCM configurations'. | ||
81 | * These configurations are characterized by voltage and speed for clocks. | ||
82 | * The device is only validated for certain combinations. One way to express | ||
83 | * these combinations is via the 'ratio's' which the clocks operate with | ||
84 | * respect to each other. These ratio sets are for a given voltage/DPLL | ||
85 | * setting. All configurations can be described by a DPLL setting and a ratio | ||
86 | * There are 3 ratio sets for the 2430 and X ratio sets for 2420. | ||
87 | * | ||
88 | * 2430 differs from 2420 in that there are no more phase synchronizers used. | ||
89 | * They both have a slightly different clock domain setup. 2420(iva1,dsp) vs | ||
90 | * 2430 (iva2.1, NOdsp, mdm) | ||
91 | */ | ||
92 | |||
93 | /* Core fields for cm_clksel, not ratio governed */ | ||
94 | #define RX_CLKSEL_DSS1 (0x10 << 8) | ||
95 | #define RX_CLKSEL_DSS2 (0x0 << 13) | ||
96 | #define RX_CLKSEL_SSI (0x5 << 20) | ||
97 | |||
98 | /*------------------------------------------------------------------------- | ||
99 | * Voltage/DPLL ratios | ||
100 | *-------------------------------------------------------------------------*/ | ||
101 | |||
102 | /* 2430 Ratio's, 2430-Ratio Config 1 */ | ||
103 | #define R1_CLKSEL_L3 (4 << 0) | ||
104 | #define R1_CLKSEL_L4 (2 << 5) | ||
105 | #define R1_CLKSEL_USB (4 << 25) | ||
106 | #define R1_CM_CLKSEL1_CORE_VAL R1_CLKSEL_USB | RX_CLKSEL_SSI | \ | ||
107 | RX_CLKSEL_DSS2 | RX_CLKSEL_DSS1 | \ | ||
108 | R1_CLKSEL_L4 | R1_CLKSEL_L3 | ||
109 | #define R1_CLKSEL_MPU (2 << 0) | ||
110 | #define R1_CM_CLKSEL_MPU_VAL R1_CLKSEL_MPU | ||
111 | #define R1_CLKSEL_DSP (2 << 0) | ||
112 | #define R1_CLKSEL_DSP_IF (2 << 5) | ||
113 | #define R1_CM_CLKSEL_DSP_VAL R1_CLKSEL_DSP | R1_CLKSEL_DSP_IF | ||
114 | #define R1_CLKSEL_GFX (2 << 0) | ||
115 | #define R1_CM_CLKSEL_GFX_VAL R1_CLKSEL_GFX | ||
116 | #define R1_CLKSEL_MDM (4 << 0) | ||
117 | #define R1_CM_CLKSEL_MDM_VAL R1_CLKSEL_MDM | ||
118 | |||
119 | /* 2430-Ratio Config 2 */ | ||
120 | #define R2_CLKSEL_L3 (6 << 0) | ||
121 | #define R2_CLKSEL_L4 (2 << 5) | ||
122 | #define R2_CLKSEL_USB (2 << 25) | ||
123 | #define R2_CM_CLKSEL1_CORE_VAL R2_CLKSEL_USB | RX_CLKSEL_SSI | \ | ||
124 | RX_CLKSEL_DSS2 | RX_CLKSEL_DSS1 | \ | ||
125 | R2_CLKSEL_L4 | R2_CLKSEL_L3 | ||
126 | #define R2_CLKSEL_MPU (2 << 0) | ||
127 | #define R2_CM_CLKSEL_MPU_VAL R2_CLKSEL_MPU | ||
128 | #define R2_CLKSEL_DSP (2 << 0) | ||
129 | #define R2_CLKSEL_DSP_IF (3 << 5) | ||
130 | #define R2_CM_CLKSEL_DSP_VAL R2_CLKSEL_DSP | R2_CLKSEL_DSP_IF | ||
131 | #define R2_CLKSEL_GFX (2 << 0) | ||
132 | #define R2_CM_CLKSEL_GFX_VAL R2_CLKSEL_GFX | ||
133 | #define R2_CLKSEL_MDM (6 << 0) | ||
134 | #define R2_CM_CLKSEL_MDM_VAL R2_CLKSEL_MDM | ||
135 | |||
136 | /* 2430-Ratio Bootm (BYPASS) */ | ||
137 | #define RB_CLKSEL_L3 (1 << 0) | ||
138 | #define RB_CLKSEL_L4 (1 << 5) | ||
139 | #define RB_CLKSEL_USB (1 << 25) | ||
140 | #define RB_CM_CLKSEL1_CORE_VAL RB_CLKSEL_USB | RX_CLKSEL_SSI | \ | ||
141 | RX_CLKSEL_DSS2 | RX_CLKSEL_DSS1 | \ | ||
142 | RB_CLKSEL_L4 | RB_CLKSEL_L3 | ||
143 | #define RB_CLKSEL_MPU (1 << 0) | ||
144 | #define RB_CM_CLKSEL_MPU_VAL RB_CLKSEL_MPU | ||
145 | #define RB_CLKSEL_DSP (1 << 0) | ||
146 | #define RB_CLKSEL_DSP_IF (1 << 5) | ||
147 | #define RB_CM_CLKSEL_DSP_VAL RB_CLKSEL_DSP | RB_CLKSEL_DSP_IF | ||
148 | #define RB_CLKSEL_GFX (1 << 0) | ||
149 | #define RB_CM_CLKSEL_GFX_VAL RB_CLKSEL_GFX | ||
150 | #define RB_CLKSEL_MDM (1 << 0) | ||
151 | #define RB_CM_CLKSEL_MDM_VAL RB_CLKSEL_MDM | ||
152 | |||
153 | /* 2420 Ratio Equivalents */ | ||
154 | #define RXX_CLKSEL_VLYNQ (0x12 << 15) | ||
155 | #define RXX_CLKSEL_SSI (0x8 << 20) | ||
156 | |||
157 | /* 2420-PRCM III 532MHz core */ | ||
158 | #define RIII_CLKSEL_L3 (4 << 0) /* 133MHz */ | ||
159 | #define RIII_CLKSEL_L4 (2 << 5) /* 66.5MHz */ | ||
160 | #define RIII_CLKSEL_USB (4 << 25) /* 33.25MHz */ | ||
161 | #define RIII_CM_CLKSEL1_CORE_VAL RIII_CLKSEL_USB | RXX_CLKSEL_SSI | \ | ||
162 | RXX_CLKSEL_VLYNQ | RX_CLKSEL_DSS2 | \ | ||
163 | RX_CLKSEL_DSS1 | RIII_CLKSEL_L4 | \ | ||
164 | RIII_CLKSEL_L3 | ||
165 | #define RIII_CLKSEL_MPU (2 << 0) /* 266MHz */ | ||
166 | #define RIII_CM_CLKSEL_MPU_VAL RIII_CLKSEL_MPU | ||
167 | #define RIII_CLKSEL_DSP (3 << 0) /* c5x - 177.3MHz */ | ||
168 | #define RIII_CLKSEL_DSP_IF (2 << 5) /* c5x - 88.67MHz */ | ||
169 | #define RIII_SYNC_DSP (1 << 7) /* Enable sync */ | ||
170 | #define RIII_CLKSEL_IVA (6 << 8) /* iva1 - 88.67MHz */ | ||
171 | #define RIII_SYNC_IVA (1 << 13) /* Enable sync */ | ||
172 | #define RIII_CM_CLKSEL_DSP_VAL RIII_SYNC_IVA | RIII_CLKSEL_IVA | \ | ||
173 | RIII_SYNC_DSP | RIII_CLKSEL_DSP_IF | \ | ||
174 | RIII_CLKSEL_DSP | ||
175 | #define RIII_CLKSEL_GFX (2 << 0) /* 66.5MHz */ | ||
176 | #define RIII_CM_CLKSEL_GFX_VAL RIII_CLKSEL_GFX | ||
177 | |||
178 | /* 2420-PRCM II 600MHz core */ | ||
179 | #define RII_CLKSEL_L3 (6 << 0) /* 100MHz */ | ||
180 | #define RII_CLKSEL_L4 (2 << 5) /* 50MHz */ | ||
181 | #define RII_CLKSEL_USB (2 << 25) /* 50MHz */ | ||
182 | #define RII_CM_CLKSEL1_CORE_VAL RII_CLKSEL_USB | \ | ||
183 | RXX_CLKSEL_SSI | RXX_CLKSEL_VLYNQ | \ | ||
184 | RX_CLKSEL_DSS2 | RX_CLKSEL_DSS1 | \ | ||
185 | RII_CLKSEL_L4 | RII_CLKSEL_L3 | ||
186 | #define RII_CLKSEL_MPU (2 << 0) /* 300MHz */ | ||
187 | #define RII_CM_CLKSEL_MPU_VAL RII_CLKSEL_MPU | ||
188 | #define RII_CLKSEL_DSP (3 << 0) /* c5x - 200MHz */ | ||
189 | #define RII_CLKSEL_DSP_IF (2 << 5) /* c5x - 100MHz */ | ||
190 | #define RII_SYNC_DSP (0 << 7) /* Bypass sync */ | ||
191 | #define RII_CLKSEL_IVA (6 << 8) /* iva1 - 200MHz */ | ||
192 | #define RII_SYNC_IVA (0 << 13) /* Bypass sync */ | ||
193 | #define RII_CM_CLKSEL_DSP_VAL RII_SYNC_IVA | RII_CLKSEL_IVA | \ | ||
194 | RII_SYNC_DSP | RII_CLKSEL_DSP_IF | \ | ||
195 | RII_CLKSEL_DSP | ||
196 | #define RII_CLKSEL_GFX (2 << 0) /* 50MHz */ | ||
197 | #define RII_CM_CLKSEL_GFX_VAL RII_CLKSEL_GFX | ||
198 | |||
199 | /* 2420-PRCM VII (boot) */ | ||
200 | #define RVII_CLKSEL_L3 (1 << 0) | ||
201 | #define RVII_CLKSEL_L4 (1 << 5) | ||
202 | #define RVII_CLKSEL_DSS1 (1 << 8) | ||
203 | #define RVII_CLKSEL_DSS2 (0 << 13) | ||
204 | #define RVII_CLKSEL_VLYNQ (1 << 15) | ||
205 | #define RVII_CLKSEL_SSI (1 << 20) | ||
206 | #define RVII_CLKSEL_USB (1 << 25) | ||
207 | |||
208 | #define RVII_CM_CLKSEL1_CORE_VAL RVII_CLKSEL_USB | RVII_CLKSEL_SSI | \ | ||
209 | RVII_CLKSEL_VLYNQ | RVII_CLKSEL_DSS2 | \ | ||
210 | RVII_CLKSEL_DSS1 | RVII_CLKSEL_L4 | RVII_CLKSEL_L3 | ||
211 | |||
212 | #define RVII_CLKSEL_MPU (1 << 0) /* all divide by 1 */ | ||
213 | #define RVII_CM_CLKSEL_MPU_VAL RVII_CLKSEL_MPU | ||
214 | |||
215 | #define RVII_CLKSEL_DSP (1 << 0) | ||
216 | #define RVII_CLKSEL_DSP_IF (1 << 5) | ||
217 | #define RVII_SYNC_DSP (0 << 7) | ||
218 | #define RVII_CLKSEL_IVA (1 << 8) | ||
219 | #define RVII_SYNC_IVA (0 << 13) | ||
220 | #define RVII_CM_CLKSEL_DSP_VAL RVII_SYNC_IVA | RVII_CLKSEL_IVA | RVII_SYNC_DSP | \ | ||
221 | RVII_CLKSEL_DSP_IF | RVII_CLKSEL_DSP | ||
222 | |||
223 | #define RVII_CLKSEL_GFX (1 << 0) | ||
224 | #define RVII_CM_CLKSEL_GFX_VAL RVII_CLKSEL_GFX | ||
225 | |||
226 | /*------------------------------------------------------------------------- | ||
227 | * 2430 Target modes: Along with each configuration the CPU has several | ||
228 | * modes which goes along with them. Modes mainly are the addition of | ||
229 | * describe DPLL combinations to go along with a ratio. | ||
230 | *-------------------------------------------------------------------------*/ | ||
231 | |||
232 | /* Hardware governed */ | ||
233 | #define MX_48M_SRC (0 << 3) | ||
234 | #define MX_54M_SRC (0 << 5) | ||
235 | #define MX_APLLS_CLIKIN_12 (3 << 23) | ||
236 | #define MX_APLLS_CLIKIN_13 (2 << 23) | ||
237 | #define MX_APLLS_CLIKIN_19_2 (0 << 23) | ||
238 | |||
239 | /* | ||
240 | * 2430 - standalone, 2*ref*M/(n+1), M/N is for exactness not relock speed | ||
241 | * #2 (ratio1) baseport-target | ||
242 | * #5a (ratio1) baseport-target, target DPLL = 266*2 = 532MHz | ||
243 | */ | ||
244 | #define M5A_DPLL_MULT_12 (133 << 12) | ||
245 | #define M5A_DPLL_DIV_12 (5 << 8) | ||
246 | #define M5A_CM_CLKSEL1_PLL_12_VAL MX_48M_SRC | MX_54M_SRC | \ | ||
247 | M5A_DPLL_DIV_12 | M5A_DPLL_MULT_12 | \ | ||
248 | MX_APLLS_CLIKIN_12 | ||
249 | #define M5A_DPLL_MULT_13 (266 << 12) | ||
250 | #define M5A_DPLL_DIV_13 (12 << 8) | ||
251 | #define M5A_CM_CLKSEL1_PLL_13_VAL MX_48M_SRC | MX_54M_SRC | \ | ||
252 | M5A_DPLL_DIV_13 | M5A_DPLL_MULT_13 | \ | ||
253 | MX_APLLS_CLIKIN_13 | ||
254 | #define M5A_DPLL_MULT_19 (180 << 12) | ||
255 | #define M5A_DPLL_DIV_19 (12 << 8) | ||
256 | #define M5A_CM_CLKSEL1_PLL_19_VAL MX_48M_SRC | MX_54M_SRC | \ | ||
257 | M5A_DPLL_DIV_19 | M5A_DPLL_MULT_19 | \ | ||
258 | MX_APLLS_CLIKIN_19_2 | ||
259 | /* #5b (ratio1) target DPLL = 200*2 = 400MHz */ | ||
260 | #define M5B_DPLL_MULT_12 (50 << 12) | ||
261 | #define M5B_DPLL_DIV_12 (2 << 8) | ||
262 | #define M5B_CM_CLKSEL1_PLL_12_VAL MX_48M_SRC | MX_54M_SRC | \ | ||
263 | M5B_DPLL_DIV_12 | M5B_DPLL_MULT_12 | \ | ||
264 | MX_APLLS_CLIKIN_12 | ||
265 | #define M5B_DPLL_MULT_13 (200 << 12) | ||
266 | #define M5B_DPLL_DIV_13 (12 << 8) | ||
267 | |||
268 | #define M5B_CM_CLKSEL1_PLL_13_VAL MX_48M_SRC | MX_54M_SRC | \ | ||
269 | M5B_DPLL_DIV_13 | M5B_DPLL_MULT_13 | \ | ||
270 | MX_APLLS_CLIKIN_13 | ||
271 | #define M5B_DPLL_MULT_19 (125 << 12) | ||
272 | #define M5B_DPLL_DIV_19 (31 << 8) | ||
273 | #define M5B_CM_CLKSEL1_PLL_19_VAL MX_48M_SRC | MX_54M_SRC | \ | ||
274 | M5B_DPLL_DIV_19 | M5B_DPLL_MULT_19 | \ | ||
275 | MX_APLLS_CLIKIN_19_2 | ||
276 | /* | ||
277 | * #4 (ratio2) | ||
278 | * #3 (ratio2) baseport-target, target DPLL = 330*2 = 660MHz | ||
279 | */ | ||
280 | #define M3_DPLL_MULT_12 (55 << 12) | ||
281 | #define M3_DPLL_DIV_12 (1 << 8) | ||
282 | #define M3_CM_CLKSEL1_PLL_12_VAL MX_48M_SRC | MX_54M_SRC | \ | ||
283 | M3_DPLL_DIV_12 | M3_DPLL_MULT_12 | \ | ||
284 | MX_APLLS_CLIKIN_12 | ||
285 | #define M3_DPLL_MULT_13 (330 << 12) | ||
286 | #define M3_DPLL_DIV_13 (12 << 8) | ||
287 | #define M3_CM_CLKSEL1_PLL_13_VAL MX_48M_SRC | MX_54M_SRC | \ | ||
288 | M3_DPLL_DIV_13 | M3_DPLL_MULT_13 | \ | ||
289 | MX_APLLS_CLIKIN_13 | ||
290 | #define M3_DPLL_MULT_19 (275 << 12) | ||
291 | #define M3_DPLL_DIV_19 (15 << 8) | ||
292 | #define M3_CM_CLKSEL1_PLL_19_VAL MX_48M_SRC | MX_54M_SRC | \ | ||
293 | M3_DPLL_DIV_19 | M3_DPLL_MULT_19 | \ | ||
294 | MX_APLLS_CLIKIN_19_2 | ||
295 | /* boot (boot) */ | ||
296 | #define MB_DPLL_MULT (1 << 12) | ||
297 | #define MB_DPLL_DIV (0 << 8) | ||
298 | #define MB_CM_CLKSEL1_PLL_12_VAL MX_48M_SRC | MX_54M_SRC | MB_DPLL_DIV |\ | ||
299 | MB_DPLL_MULT | MX_APLLS_CLIKIN_12 | ||
300 | |||
301 | #define MB_CM_CLKSEL1_PLL_13_VAL MX_48M_SRC | MX_54M_SRC | MB_DPLL_DIV |\ | ||
302 | MB_DPLL_MULT | MX_APLLS_CLIKIN_13 | ||
303 | |||
304 | #define MB_CM_CLKSEL1_PLL_19_VAL MX_48M_SRC | MX_54M_SRC | MB_DPLL_DIV |\ | ||
305 | MB_DPLL_MULT | MX_APLLS_CLIKIN_19 | ||
306 | |||
307 | /* | ||
308 | * 2430 - chassis (sedna) | ||
309 | * 165 (ratio1) same as above #2 | ||
310 | * 150 (ratio1) | ||
311 | * 133 (ratio2) same as above #4 | ||
312 | * 110 (ratio2) same as above #3 | ||
313 | * 104 (ratio2) | ||
314 | * boot (boot) | ||
315 | */ | ||
316 | |||
317 | /* | ||
318 | * 2420 Equivalent - mode registers | ||
319 | * PRCM II , target DPLL = 2*300MHz = 600MHz | ||
320 | */ | ||
321 | #define MII_DPLL_MULT_12 (50 << 12) | ||
322 | #define MII_DPLL_DIV_12 (1 << 8) | ||
323 | #define MII_CM_CLKSEL1_PLL_12_VAL MX_48M_SRC | MX_54M_SRC | \ | ||
324 | MII_DPLL_DIV_12 | MII_DPLL_MULT_12 | \ | ||
325 | MX_APLLS_CLIKIN_12 | ||
326 | #define MII_DPLL_MULT_13 (300 << 12) | ||
327 | #define MII_DPLL_DIV_13 (12 << 8) | ||
328 | #define MII_CM_CLKSEL1_PLL_13_VAL MX_48M_SRC | MX_54M_SRC | \ | ||
329 | MII_DPLL_DIV_13 | MII_DPLL_MULT_13 | \ | ||
330 | MX_APLLS_CLIKIN_13 | ||
331 | |||
332 | /* PRCM III target DPLL = 2*266 = 532MHz*/ | ||
333 | #define MIII_DPLL_MULT_12 (133 << 12) | ||
334 | #define MIII_DPLL_DIV_12 (5 << 8) | ||
335 | #define MIII_CM_CLKSEL1_PLL_12_VAL MX_48M_SRC | MX_54M_SRC | \ | ||
336 | MIII_DPLL_DIV_12 | MIII_DPLL_MULT_12 | \ | ||
337 | MX_APLLS_CLIKIN_12 | ||
338 | #define MIII_DPLL_MULT_13 (266 << 12) | ||
339 | #define MIII_DPLL_DIV_13 (12 << 8) | ||
340 | #define MIII_CM_CLKSEL1_PLL_13_VAL MX_48M_SRC | MX_54M_SRC | \ | ||
341 | MIII_DPLL_DIV_13 | MIII_DPLL_MULT_13 | \ | ||
342 | MX_APLLS_CLIKIN_13 | ||
343 | |||
344 | /* PRCM VII (boot bypass) */ | ||
345 | #define MVII_CM_CLKSEL1_PLL_12_VAL MB_CM_CLKSEL1_PLL_12_VAL | ||
346 | #define MVII_CM_CLKSEL1_PLL_13_VAL MB_CM_CLKSEL1_PLL_13_VAL | ||
347 | |||
348 | /* High and low operation value */ | ||
349 | #define MX_CLKSEL2_PLL_2x_VAL (2 << 0) | ||
350 | #define MX_CLKSEL2_PLL_1x_VAL (1 << 0) | ||
351 | |||
352 | /* | ||
353 | * These represent optimal values for common parts, it won't work for all. | ||
354 | * As long as you scale down, most parameters are still work, they just | ||
355 | * become sub-optimal. The RFR value goes in the oppisite direction. If you | ||
356 | * don't adjust it down as your clock period increases the refresh interval | ||
357 | * will not be met. Setting all parameters for complete worst case may work, | ||
358 | * but may cut memory performance by 2x. Due to errata the DLLs need to be | ||
359 | * unlocked and their value needs run time calibration. A dynamic call is | ||
360 | * need for that as no single right value exists acorss production samples. | ||
361 | * | ||
362 | * Only the FULL speed values are given. Current code is such that rate | ||
363 | * changes must be made at DPLLoutx2. The actual value adjustment for low | ||
364 | * frequency operation will be handled by omap_set_performance() | ||
365 | * | ||
366 | * By having the boot loader boot up in the fastest L4 speed available likely | ||
367 | * will result in something which you can switch between. | ||
368 | */ | ||
369 | #define V24XX_SDRC_RFR_CTRL_133MHz (0x0003de00 | 1) | ||
370 | #define V24XX_SDRC_RFR_CTRL_100MHz (0x0002da01 | 1) | ||
371 | #define V24XX_SDRC_RFR_CTRL_110MHz (0x0002da01 | 1) /* Need to calc */ | ||
372 | #define V24XX_SDRC_RFR_CTRL_BYPASS (0x00005000 | 1) /* Need to calc */ | ||
373 | |||
374 | /* MPU speed defines */ | ||
375 | #define S12M 12000000 | ||
376 | #define S13M 13000000 | ||
377 | #define S19M 19200000 | ||
378 | #define S26M 26000000 | ||
379 | #define S100M 100000000 | ||
380 | #define S133M 133000000 | ||
381 | #define S150M 150000000 | ||
382 | #define S165M 165000000 | ||
383 | #define S200M 200000000 | ||
384 | #define S266M 266000000 | ||
385 | #define S300M 300000000 | ||
386 | #define S330M 330000000 | ||
387 | #define S400M 400000000 | ||
388 | #define S532M 532000000 | ||
389 | #define S600M 600000000 | ||
390 | #define S660M 660000000 | ||
391 | |||
392 | /*------------------------------------------------------------------------- | ||
393 | * Key dividers which make up a PRCM set. Ratio's for a PRCM are mandated. | ||
394 | * xtal_speed, dpll_speed, mpu_speed, CM_CLKSEL_MPU, | ||
395 | * CM_CLKSEL_DSP, CM_CLKSEL_GFX, CM_CLKSEL1_CORE, CM_CLKSEL1_PLL, | ||
396 | * CM_CLKSEL2_PLL, CM_CLKSEL_MDM | ||
397 | * | ||
398 | * Filling in table based on H4 boards and 2430-SDPs variants available. | ||
399 | * There are quite a few more rates combinations which could be defined. | ||
400 | * | ||
401 | * When multiple values are defiend the start up will try and choose the | ||
402 | * fastest one. If a 'fast' value is defined, then automatically, the /2 | ||
403 | * one should be included as it can be used. Generally having more that | ||
404 | * one fast set does not make sense, as static timings need to be changed | ||
405 | * to change the set. The exception is the bypass setting which is | ||
406 | * availble for low power bypass. | ||
407 | * | ||
408 | * Note: This table needs to be sorted, fastest to slowest. | ||
409 | *-------------------------------------------------------------------------*/ | ||
410 | static struct prcm_config rate_table[] = { | ||
411 | /* PRCM II - FAST */ | ||
412 | {S12M, S600M, S300M, RII_CM_CLKSEL_MPU_VAL, /* 300MHz ARM */ | ||
413 | RII_CM_CLKSEL_DSP_VAL, RII_CM_CLKSEL_GFX_VAL, | ||
414 | RII_CM_CLKSEL1_CORE_VAL, MII_CM_CLKSEL1_PLL_12_VAL, | ||
415 | MX_CLKSEL2_PLL_2x_VAL, 0, V24XX_SDRC_RFR_CTRL_100MHz, | ||
416 | RATE_IN_242X}, | ||
417 | |||
418 | {S13M, S600M, S300M, RII_CM_CLKSEL_MPU_VAL, /* 300MHz ARM */ | ||
419 | RII_CM_CLKSEL_DSP_VAL, RII_CM_CLKSEL_GFX_VAL, | ||
420 | RII_CM_CLKSEL1_CORE_VAL, MII_CM_CLKSEL1_PLL_13_VAL, | ||
421 | MX_CLKSEL2_PLL_2x_VAL, 0, V24XX_SDRC_RFR_CTRL_100MHz, | ||
422 | RATE_IN_242X}, | ||
423 | |||
424 | /* PRCM III - FAST */ | ||
425 | {S12M, S532M, S266M, RIII_CM_CLKSEL_MPU_VAL, /* 266MHz ARM */ | ||
426 | RIII_CM_CLKSEL_DSP_VAL, RIII_CM_CLKSEL_GFX_VAL, | ||
427 | RIII_CM_CLKSEL1_CORE_VAL, MIII_CM_CLKSEL1_PLL_12_VAL, | ||
428 | MX_CLKSEL2_PLL_2x_VAL, 0, V24XX_SDRC_RFR_CTRL_133MHz, | ||
429 | RATE_IN_242X}, | ||
430 | |||
431 | {S13M, S532M, S266M, RIII_CM_CLKSEL_MPU_VAL, /* 266MHz ARM */ | ||
432 | RIII_CM_CLKSEL_DSP_VAL, RIII_CM_CLKSEL_GFX_VAL, | ||
433 | RIII_CM_CLKSEL1_CORE_VAL, MIII_CM_CLKSEL1_PLL_13_VAL, | ||
434 | MX_CLKSEL2_PLL_2x_VAL, 0, V24XX_SDRC_RFR_CTRL_133MHz, | ||
435 | RATE_IN_242X}, | ||
436 | |||
437 | /* PRCM II - SLOW */ | ||
438 | {S12M, S300M, S150M, RII_CM_CLKSEL_MPU_VAL, /* 150MHz ARM */ | ||
439 | RII_CM_CLKSEL_DSP_VAL, RII_CM_CLKSEL_GFX_VAL, | ||
440 | RII_CM_CLKSEL1_CORE_VAL, MII_CM_CLKSEL1_PLL_12_VAL, | ||
441 | MX_CLKSEL2_PLL_2x_VAL, 0, V24XX_SDRC_RFR_CTRL_100MHz, | ||
442 | RATE_IN_242X}, | ||
443 | |||
444 | {S13M, S300M, S150M, RII_CM_CLKSEL_MPU_VAL, /* 150MHz ARM */ | ||
445 | RII_CM_CLKSEL_DSP_VAL, RII_CM_CLKSEL_GFX_VAL, | ||
446 | RII_CM_CLKSEL1_CORE_VAL, MII_CM_CLKSEL1_PLL_13_VAL, | ||
447 | MX_CLKSEL2_PLL_2x_VAL, 0, V24XX_SDRC_RFR_CTRL_100MHz, | ||
448 | RATE_IN_242X}, | ||
449 | |||
450 | /* PRCM III - SLOW */ | ||
451 | {S12M, S266M, S133M, RIII_CM_CLKSEL_MPU_VAL, /* 133MHz ARM */ | ||
452 | RIII_CM_CLKSEL_DSP_VAL, RIII_CM_CLKSEL_GFX_VAL, | ||
453 | RIII_CM_CLKSEL1_CORE_VAL, MIII_CM_CLKSEL1_PLL_12_VAL, | ||
454 | MX_CLKSEL2_PLL_2x_VAL, 0, V24XX_SDRC_RFR_CTRL_133MHz, | ||
455 | RATE_IN_242X}, | ||
456 | |||
457 | {S13M, S266M, S133M, RIII_CM_CLKSEL_MPU_VAL, /* 133MHz ARM */ | ||
458 | RIII_CM_CLKSEL_DSP_VAL, RIII_CM_CLKSEL_GFX_VAL, | ||
459 | RIII_CM_CLKSEL1_CORE_VAL, MIII_CM_CLKSEL1_PLL_13_VAL, | ||
460 | MX_CLKSEL2_PLL_2x_VAL, 0, V24XX_SDRC_RFR_CTRL_133MHz, | ||
461 | RATE_IN_242X}, | ||
462 | |||
463 | /* PRCM-VII (boot-bypass) */ | ||
464 | {S12M, S12M, S12M, RVII_CM_CLKSEL_MPU_VAL, /* 12MHz ARM*/ | ||
465 | RVII_CM_CLKSEL_DSP_VAL, RVII_CM_CLKSEL_GFX_VAL, | ||
466 | RVII_CM_CLKSEL1_CORE_VAL, MVII_CM_CLKSEL1_PLL_12_VAL, | ||
467 | MX_CLKSEL2_PLL_2x_VAL, 0, V24XX_SDRC_RFR_CTRL_BYPASS, | ||
468 | RATE_IN_242X}, | ||
469 | |||
470 | /* PRCM-VII (boot-bypass) */ | ||
471 | {S13M, S13M, S13M, RVII_CM_CLKSEL_MPU_VAL, /* 13MHz ARM */ | ||
472 | RVII_CM_CLKSEL_DSP_VAL, RVII_CM_CLKSEL_GFX_VAL, | ||
473 | RVII_CM_CLKSEL1_CORE_VAL, MVII_CM_CLKSEL1_PLL_13_VAL, | ||
474 | MX_CLKSEL2_PLL_2x_VAL, 0, V24XX_SDRC_RFR_CTRL_BYPASS, | ||
475 | RATE_IN_242X}, | ||
476 | |||
477 | /* PRCM #3 - ratio2 (ES2) - FAST */ | ||
478 | {S13M, S660M, S330M, R2_CM_CLKSEL_MPU_VAL, /* 330MHz ARM */ | ||
479 | R2_CM_CLKSEL_DSP_VAL, R2_CM_CLKSEL_GFX_VAL, | ||
480 | R2_CM_CLKSEL1_CORE_VAL, M3_CM_CLKSEL1_PLL_13_VAL, | ||
481 | MX_CLKSEL2_PLL_2x_VAL, R2_CM_CLKSEL_MDM_VAL, | ||
482 | V24XX_SDRC_RFR_CTRL_110MHz, | ||
483 | RATE_IN_243X}, | ||
484 | |||
485 | /* PRCM #5a - ratio1 - FAST */ | ||
486 | {S13M, S532M, S266M, R1_CM_CLKSEL_MPU_VAL, /* 266MHz ARM */ | ||
487 | R1_CM_CLKSEL_DSP_VAL, R1_CM_CLKSEL_GFX_VAL, | ||
488 | R1_CM_CLKSEL1_CORE_VAL, M5A_CM_CLKSEL1_PLL_13_VAL, | ||
489 | MX_CLKSEL2_PLL_2x_VAL, R1_CM_CLKSEL_MDM_VAL, | ||
490 | V24XX_SDRC_RFR_CTRL_133MHz, | ||
491 | RATE_IN_243X}, | ||
492 | |||
493 | /* PRCM #5b - ratio1 - FAST */ | ||
494 | {S13M, S400M, S200M, R1_CM_CLKSEL_MPU_VAL, /* 200MHz ARM */ | ||
495 | R1_CM_CLKSEL_DSP_VAL, R1_CM_CLKSEL_GFX_VAL, | ||
496 | R1_CM_CLKSEL1_CORE_VAL, M5B_CM_CLKSEL1_PLL_13_VAL, | ||
497 | MX_CLKSEL2_PLL_2x_VAL, R1_CM_CLKSEL_MDM_VAL, | ||
498 | V24XX_SDRC_RFR_CTRL_100MHz, | ||
499 | RATE_IN_243X}, | ||
500 | |||
501 | /* PRCM #3 - ratio2 (ES2) - SLOW */ | ||
502 | {S13M, S330M, S165M, R2_CM_CLKSEL_MPU_VAL, /* 165MHz ARM */ | ||
503 | R2_CM_CLKSEL_DSP_VAL, R2_CM_CLKSEL_GFX_VAL, | ||
504 | R2_CM_CLKSEL1_CORE_VAL, M3_CM_CLKSEL1_PLL_13_VAL, | ||
505 | MX_CLKSEL2_PLL_1x_VAL, R2_CM_CLKSEL_MDM_VAL, | ||
506 | V24XX_SDRC_RFR_CTRL_110MHz, | ||
507 | RATE_IN_243X}, | ||
508 | |||
509 | /* PRCM #5a - ratio1 - SLOW */ | ||
510 | {S13M, S266M, S133M, R1_CM_CLKSEL_MPU_VAL, /* 133MHz ARM */ | ||
511 | R1_CM_CLKSEL_DSP_VAL, R1_CM_CLKSEL_GFX_VAL, | ||
512 | R1_CM_CLKSEL1_CORE_VAL, M5A_CM_CLKSEL1_PLL_13_VAL, | ||
513 | MX_CLKSEL2_PLL_1x_VAL, R1_CM_CLKSEL_MDM_VAL, | ||
514 | V24XX_SDRC_RFR_CTRL_133MHz, | ||
515 | RATE_IN_243X}, | ||
516 | |||
517 | /* PRCM #5b - ratio1 - SLOW*/ | ||
518 | {S13M, S200M, S100M, R1_CM_CLKSEL_MPU_VAL, /* 100MHz ARM */ | ||
519 | R1_CM_CLKSEL_DSP_VAL, R1_CM_CLKSEL_GFX_VAL, | ||
520 | R1_CM_CLKSEL1_CORE_VAL, M5B_CM_CLKSEL1_PLL_13_VAL, | ||
521 | MX_CLKSEL2_PLL_1x_VAL, R1_CM_CLKSEL_MDM_VAL, | ||
522 | V24XX_SDRC_RFR_CTRL_100MHz, | ||
523 | RATE_IN_243X}, | ||
524 | |||
525 | /* PRCM-boot/bypass */ | ||
526 | {S13M, S13M, S13M, RB_CM_CLKSEL_MPU_VAL, /* 13Mhz */ | ||
527 | RB_CM_CLKSEL_DSP_VAL, RB_CM_CLKSEL_GFX_VAL, | ||
528 | RB_CM_CLKSEL1_CORE_VAL, MB_CM_CLKSEL1_PLL_13_VAL, | ||
529 | MX_CLKSEL2_PLL_2x_VAL, RB_CM_CLKSEL_MDM_VAL, | ||
530 | V24XX_SDRC_RFR_CTRL_BYPASS, | ||
531 | RATE_IN_243X}, | ||
532 | |||
533 | /* PRCM-boot/bypass */ | ||
534 | {S12M, S12M, S12M, RB_CM_CLKSEL_MPU_VAL, /* 12Mhz */ | ||
535 | RB_CM_CLKSEL_DSP_VAL, RB_CM_CLKSEL_GFX_VAL, | ||
536 | RB_CM_CLKSEL1_CORE_VAL, MB_CM_CLKSEL1_PLL_12_VAL, | ||
537 | MX_CLKSEL2_PLL_2x_VAL, RB_CM_CLKSEL_MDM_VAL, | ||
538 | V24XX_SDRC_RFR_CTRL_BYPASS, | ||
539 | RATE_IN_243X}, | ||
540 | |||
541 | { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
542 | }; | ||
543 | |||
544 | /*------------------------------------------------------------------------- | ||
545 | * 24xx clock tree. | ||
546 | * | ||
547 | * NOTE:In many cases here we are assigning a 'default' parent. In many | ||
548 | * cases the parent is selectable. The get/set parent calls will also | ||
549 | * switch sources. | ||
550 | * | ||
551 | * Many some clocks say always_enabled, but they can be auto idled for | ||
552 | * power savings. They will always be available upon clock request. | ||
553 | * | ||
554 | * Several sources are given initial rates which may be wrong, this will | ||
555 | * be fixed up in the init func. | ||
556 | * | ||
557 | * Things are broadly separated below by clock domains. It is | ||
558 | * noteworthy that most periferals have dependencies on multiple clock | ||
559 | * domains. Many get their interface clocks from the L4 domain, but get | ||
560 | * functional clocks from fixed sources or other core domain derived | ||
561 | * clocks. | ||
562 | *-------------------------------------------------------------------------*/ | ||
563 | |||
564 | /* Base external input clocks */ | ||
565 | static struct clk func_32k_ck = { | ||
566 | .name = "func_32k_ck", | ||
567 | .rate = 32000, | ||
568 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
569 | RATE_FIXED | ALWAYS_ENABLED, | ||
570 | }; | ||
571 | |||
572 | /* Typical 12/13MHz in standalone mode, will be 26Mhz in chassis mode */ | ||
573 | static struct clk osc_ck = { /* (*12, *13, 19.2, *26, 38.4)MHz */ | ||
574 | .name = "osc_ck", | ||
575 | .rate = 26000000, /* fixed up in clock init */ | ||
576 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
577 | RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES, | ||
578 | }; | ||
579 | |||
580 | /* With out modem likely 12MHz, with modem likely 13MHz */ | ||
581 | static struct clk sys_ck = { /* (*12, *13, 19.2, 26, 38.4)MHz */ | ||
582 | .name = "sys_ck", /* ~ ref_clk also */ | ||
583 | .parent = &osc_ck, | ||
584 | .rate = 13000000, | ||
585 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
586 | RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES, | ||
587 | .rate_offset = 6, /* sysclkdiv 1 or 2, already handled or no boot */ | ||
588 | .recalc = &omap2_sys_clk_recalc, | ||
589 | }; | ||
590 | |||
591 | static struct clk alt_ck = { /* Typical 54M or 48M, may not exist */ | ||
592 | .name = "alt_ck", | ||
593 | .rate = 54000000, | ||
594 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
595 | RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES, | ||
596 | .recalc = &omap2_propagate_rate, | ||
597 | }; | ||
598 | |||
599 | /* | ||
600 | * Analog domain root source clocks | ||
601 | */ | ||
602 | |||
603 | /* dpll_ck, is broken out in to special cases through clksel */ | ||
604 | static struct clk dpll_ck = { | ||
605 | .name = "dpll_ck", | ||
606 | .parent = &sys_ck, /* Can be func_32k also */ | ||
607 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
608 | RATE_PROPAGATES | RATE_CKCTL | CM_PLL_SEL1, | ||
609 | .recalc = &omap2_clksel_recalc, | ||
610 | }; | ||
611 | |||
612 | static struct clk apll96_ck = { | ||
613 | .name = "apll96_ck", | ||
614 | .parent = &sys_ck, | ||
615 | .rate = 96000000, | ||
616 | .flags = CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X | | ||
617 | RATE_FIXED | RATE_PROPAGATES, | ||
618 | .enable_reg = (void __iomem *)&CM_CLKEN_PLL, | ||
619 | .enable_bit = 0x2, | ||
620 | .recalc = &omap2_propagate_rate, | ||
621 | }; | ||
622 | |||
623 | static struct clk apll54_ck = { | ||
624 | .name = "apll54_ck", | ||
625 | .parent = &sys_ck, | ||
626 | .rate = 54000000, | ||
627 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
628 | RATE_FIXED | RATE_PROPAGATES, | ||
629 | .enable_reg = (void __iomem *)&CM_CLKEN_PLL, | ||
630 | .enable_bit = 0x6, | ||
631 | .recalc = &omap2_propagate_rate, | ||
632 | }; | ||
633 | |||
634 | /* | ||
635 | * PRCM digital base sources | ||
636 | */ | ||
637 | static struct clk func_54m_ck = { | ||
638 | .name = "func_54m_ck", | ||
639 | .parent = &apll54_ck, /* can also be alt_clk */ | ||
640 | .rate = 54000000, | ||
641 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
642 | RATE_FIXED | CM_PLL_SEL1 | RATE_PROPAGATES, | ||
643 | .src_offset = 5, | ||
644 | .enable_reg = (void __iomem *)&CM_CLKEN_PLL, | ||
645 | .enable_bit = 0xff, | ||
646 | .recalc = &omap2_propagate_rate, | ||
647 | }; | ||
648 | |||
649 | static struct clk core_ck = { | ||
650 | .name = "core_ck", | ||
651 | .parent = &dpll_ck, /* can also be 32k */ | ||
652 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
653 | ALWAYS_ENABLED | RATE_PROPAGATES, | ||
654 | .recalc = &omap2_propagate_rate, | ||
655 | }; | ||
656 | |||
657 | static struct clk sleep_ck = { /* sys_clk or 32k */ | ||
658 | .name = "sleep_ck", | ||
659 | .parent = &func_32k_ck, | ||
660 | .rate = 32000, | ||
661 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
662 | .recalc = &omap2_propagate_rate, | ||
663 | }; | ||
664 | |||
665 | static struct clk func_96m_ck = { | ||
666 | .name = "func_96m_ck", | ||
667 | .parent = &apll96_ck, | ||
668 | .rate = 96000000, | ||
669 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
670 | RATE_FIXED | RATE_PROPAGATES, | ||
671 | .enable_reg = (void __iomem *)&CM_CLKEN_PLL, | ||
672 | .enable_bit = 0xff, | ||
673 | .recalc = &omap2_propagate_rate, | ||
674 | }; | ||
675 | |||
676 | static struct clk func_48m_ck = { | ||
677 | .name = "func_48m_ck", | ||
678 | .parent = &apll96_ck, /* 96M or Alt */ | ||
679 | .rate = 48000000, | ||
680 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
681 | RATE_FIXED | CM_PLL_SEL1 | RATE_PROPAGATES, | ||
682 | .src_offset = 3, | ||
683 | .enable_reg = (void __iomem *)&CM_CLKEN_PLL, | ||
684 | .enable_bit = 0xff, | ||
685 | .recalc = &omap2_propagate_rate, | ||
686 | }; | ||
687 | |||
688 | static struct clk func_12m_ck = { | ||
689 | .name = "func_12m_ck", | ||
690 | .parent = &func_48m_ck, | ||
691 | .rate = 12000000, | ||
692 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
693 | RATE_FIXED | RATE_PROPAGATES, | ||
694 | .recalc = &omap2_propagate_rate, | ||
695 | .enable_reg = (void __iomem *)&CM_CLKEN_PLL, | ||
696 | .enable_bit = 0xff, | ||
697 | }; | ||
698 | |||
699 | /* Secure timer, only available in secure mode */ | ||
700 | static struct clk wdt1_osc_ck = { | ||
701 | .name = "ck_wdt1_osc", | ||
702 | .parent = &osc_ck, | ||
703 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
704 | .recalc = &omap2_followparent_recalc, | ||
705 | }; | ||
706 | |||
707 | static struct clk sys_clkout = { | ||
708 | .name = "sys_clkout", | ||
709 | .parent = &func_54m_ck, | ||
710 | .rate = 54000000, | ||
711 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
712 | CM_SYSCLKOUT_SEL1 | RATE_CKCTL, | ||
713 | .src_offset = 0, | ||
714 | .enable_reg = (void __iomem *)&PRCM_CLKOUT_CTRL, | ||
715 | .enable_bit = 7, | ||
716 | .rate_offset = 3, | ||
717 | .recalc = &omap2_clksel_recalc, | ||
718 | }; | ||
719 | |||
720 | /* In 2430, new in 2420 ES2 */ | ||
721 | static struct clk sys_clkout2 = { | ||
722 | .name = "sys_clkout2", | ||
723 | .parent = &func_54m_ck, | ||
724 | .rate = 54000000, | ||
725 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
726 | CM_SYSCLKOUT_SEL1 | RATE_CKCTL, | ||
727 | .src_offset = 8, | ||
728 | .enable_reg = (void __iomem *)&PRCM_CLKOUT_CTRL, | ||
729 | .enable_bit = 15, | ||
730 | .rate_offset = 11, | ||
731 | .recalc = &omap2_clksel_recalc, | ||
732 | }; | ||
733 | |||
734 | /* | ||
735 | * MPU clock domain | ||
736 | * Clocks: | ||
737 | * MPU_FCLK, MPU_ICLK | ||
738 | * INT_M_FCLK, INT_M_I_CLK | ||
739 | * | ||
740 | * - Individual clocks are hardware managed. | ||
741 | * - Base divider comes from: CM_CLKSEL_MPU | ||
742 | * | ||
743 | */ | ||
744 | static struct clk mpu_ck = { /* Control cpu */ | ||
745 | .name = "mpu_ck", | ||
746 | .parent = &core_ck, | ||
747 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | RATE_CKCTL | | ||
748 | ALWAYS_ENABLED | CM_MPU_SEL1 | DELAYED_APP | | ||
749 | CONFIG_PARTICIPANT | RATE_PROPAGATES, | ||
750 | .rate_offset = 0, /* bits 0-4 */ | ||
751 | .recalc = &omap2_clksel_recalc, | ||
752 | }; | ||
753 | |||
754 | /* | ||
755 | * DSP (2430-IVA2.1) (2420-UMA+IVA1) clock domain | ||
756 | * Clocks: | ||
757 | * 2430: IVA2.1_FCLK, IVA2.1_ICLK | ||
758 | * 2420: UMA_FCLK, UMA_ICLK, IVA_MPU, IVA_COP | ||
759 | */ | ||
760 | static struct clk iva2_1_fck = { | ||
761 | .name = "iva2_1_fck", | ||
762 | .parent = &core_ck, | ||
763 | .flags = CLOCK_IN_OMAP243X | RATE_CKCTL | CM_DSP_SEL1 | | ||
764 | DELAYED_APP | RATE_PROPAGATES | | ||
765 | CONFIG_PARTICIPANT, | ||
766 | .rate_offset = 0, | ||
767 | .enable_reg = (void __iomem *)&CM_FCLKEN_DSP, | ||
768 | .enable_bit = 0, | ||
769 | .recalc = &omap2_clksel_recalc, | ||
770 | }; | ||
771 | |||
772 | static struct clk iva2_1_ick = { | ||
773 | .name = "iva2_1_ick", | ||
774 | .parent = &iva2_1_fck, | ||
775 | .flags = CLOCK_IN_OMAP243X | RATE_CKCTL | CM_DSP_SEL1 | | ||
776 | DELAYED_APP | CONFIG_PARTICIPANT, | ||
777 | .rate_offset = 5, | ||
778 | .recalc = &omap2_clksel_recalc, | ||
779 | }; | ||
780 | |||
781 | /* | ||
782 | * Won't be too specific here. The core clock comes into this block | ||
783 | * it is divided then tee'ed. One branch goes directly to xyz enable | ||
784 | * controls. The other branch gets further divided by 2 then possibly | ||
785 | * routed into a synchronizer and out of clocks abc. | ||
786 | */ | ||
787 | static struct clk dsp_fck = { | ||
788 | .name = "dsp_fck", | ||
789 | .parent = &core_ck, | ||
790 | .flags = CLOCK_IN_OMAP242X | RATE_CKCTL | CM_DSP_SEL1 | | ||
791 | DELAYED_APP | CONFIG_PARTICIPANT | RATE_PROPAGATES, | ||
792 | .rate_offset = 0, | ||
793 | .enable_reg = (void __iomem *)&CM_FCLKEN_DSP, | ||
794 | .enable_bit = 0, | ||
795 | .recalc = &omap2_clksel_recalc, | ||
796 | }; | ||
797 | |||
798 | static struct clk dsp_ick = { | ||
799 | .name = "dsp_ick", /* apparently ipi and isp */ | ||
800 | .parent = &dsp_fck, | ||
801 | .flags = CLOCK_IN_OMAP242X | RATE_CKCTL | CM_DSP_SEL1 | | ||
802 | DELAYED_APP | CONFIG_PARTICIPANT, | ||
803 | .rate_offset = 5, | ||
804 | .enable_reg = (void __iomem *)&CM_ICLKEN_DSP, | ||
805 | .enable_bit = 1, /* for ipi */ | ||
806 | .recalc = &omap2_clksel_recalc, | ||
807 | }; | ||
808 | |||
809 | static struct clk iva1_ifck = { | ||
810 | .name = "iva1_ifck", | ||
811 | .parent = &core_ck, | ||
812 | .flags = CLOCK_IN_OMAP242X | CM_DSP_SEL1 | RATE_CKCTL | | ||
813 | CONFIG_PARTICIPANT | RATE_PROPAGATES | DELAYED_APP, | ||
814 | .rate_offset= 8, | ||
815 | .enable_reg = (void __iomem *)&CM_FCLKEN_DSP, | ||
816 | .enable_bit = 10, | ||
817 | .recalc = &omap2_clksel_recalc, | ||
818 | }; | ||
819 | |||
820 | /* IVA1 mpu/int/i/f clocks are /2 of parent */ | ||
821 | static struct clk iva1_mpu_int_ifck = { | ||
822 | .name = "iva1_mpu_int_ifck", | ||
823 | .parent = &iva1_ifck, | ||
824 | .flags = CLOCK_IN_OMAP242X | RATE_CKCTL | CM_DSP_SEL1, | ||
825 | .enable_reg = (void __iomem *)&CM_FCLKEN_DSP, | ||
826 | .enable_bit = 8, | ||
827 | .recalc = &omap2_clksel_recalc, | ||
828 | }; | ||
829 | |||
830 | /* | ||
831 | * L3 clock domain | ||
832 | * L3 clocks are used for both interface and functional clocks to | ||
833 | * multiple entities. Some of these clocks are completely managed | ||
834 | * by hardware, and some others allow software control. Hardware | ||
835 | * managed ones general are based on directly CLK_REQ signals and | ||
836 | * various auto idle settings. The functional spec sets many of these | ||
837 | * as 'tie-high' for their enables. | ||
838 | * | ||
839 | * I-CLOCKS: | ||
840 | * L3-Interconnect, SMS, GPMC, SDRC, OCM_RAM, OCM_ROM, SDMA | ||
841 | * CAM, HS-USB. | ||
842 | * F-CLOCK | ||
843 | * SSI. | ||
844 | * | ||
845 | * GPMC memories and SDRC have timing and clock sensitive registers which | ||
846 | * may very well need notification when the clock changes. Currently for low | ||
847 | * operating points, these are taken care of in sleep.S. | ||
848 | */ | ||
849 | static struct clk core_l3_ck = { /* Used for ick and fck, interconnect */ | ||
850 | .name = "core_l3_ck", | ||
851 | .parent = &core_ck, | ||
852 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
853 | RATE_CKCTL | ALWAYS_ENABLED | CM_CORE_SEL1 | | ||
854 | DELAYED_APP | CONFIG_PARTICIPANT | | ||
855 | RATE_PROPAGATES, | ||
856 | .rate_offset = 0, | ||
857 | .recalc = &omap2_clksel_recalc, | ||
858 | }; | ||
859 | |||
860 | static struct clk usb_l4_ick = { /* FS-USB interface clock */ | ||
861 | .name = "usb_l4_ick", | ||
862 | .parent = &core_ck, | ||
863 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
864 | RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP | | ||
865 | CONFIG_PARTICIPANT, | ||
866 | .enable_reg = (void __iomem *)&CM_ICLKEN2_CORE, | ||
867 | .enable_bit = 0, | ||
868 | .rate_offset = 25, | ||
869 | .recalc = &omap2_clksel_recalc, | ||
870 | }; | ||
871 | |||
872 | /* | ||
873 | * SSI is in L3 management domain, its direct parent is core not l3, | ||
874 | * many core power domain entities are grouped into the L3 clock | ||
875 | * domain. | ||
876 | * SSI_SSR_FCLK, SSI_SST_FCLK, SSI_L4_CLIK | ||
877 | * | ||
878 | * ssr = core/1/2/3/4/5, sst = 1/2 ssr. | ||
879 | */ | ||
880 | static struct clk ssi_ssr_sst_fck = { | ||
881 | .name = "ssi_fck", | ||
882 | .parent = &core_ck, | ||
883 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
884 | RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP, | ||
885 | .enable_reg = (void __iomem *)&CM_FCLKEN2_CORE, /* bit 1 */ | ||
886 | .enable_bit = 1, | ||
887 | .rate_offset = 20, | ||
888 | .recalc = &omap2_clksel_recalc, | ||
889 | }; | ||
890 | |||
891 | /* | ||
892 | * GFX clock domain | ||
893 | * Clocks: | ||
894 | * GFX_FCLK, GFX_ICLK | ||
895 | * GFX_CG1(2d), GFX_CG2(3d) | ||
896 | * | ||
897 | * GFX_FCLK runs from L3, and is divided by (1,2,3,4) | ||
898 | * The 2d and 3d clocks run at a hardware determined | ||
899 | * divided value of fclk. | ||
900 | * | ||
901 | */ | ||
902 | static struct clk gfx_3d_fck = { | ||
903 | .name = "gfx_3d_fck", | ||
904 | .parent = &core_l3_ck, | ||
905 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
906 | RATE_CKCTL | CM_GFX_SEL1, | ||
907 | .enable_reg = (void __iomem *)&CM_FCLKEN_GFX, | ||
908 | .enable_bit = 2, | ||
909 | .rate_offset= 0, | ||
910 | .recalc = &omap2_clksel_recalc, | ||
911 | }; | ||
912 | |||
913 | static struct clk gfx_2d_fck = { | ||
914 | .name = "gfx_2d_fck", | ||
915 | .parent = &core_l3_ck, | ||
916 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
917 | RATE_CKCTL | CM_GFX_SEL1, | ||
918 | .enable_reg = (void __iomem *)&CM_FCLKEN_GFX, | ||
919 | .enable_bit = 1, | ||
920 | .rate_offset= 0, | ||
921 | .recalc = &omap2_clksel_recalc, | ||
922 | }; | ||
923 | |||
924 | static struct clk gfx_ick = { | ||
925 | .name = "gfx_ick", /* From l3 */ | ||
926 | .parent = &core_l3_ck, | ||
927 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
928 | RATE_CKCTL, | ||
929 | .enable_reg = (void __iomem *)&CM_ICLKEN_GFX, /* bit 0 */ | ||
930 | .enable_bit = 0, | ||
931 | .recalc = &omap2_followparent_recalc, | ||
932 | }; | ||
933 | |||
934 | /* | ||
935 | * Modem clock domain (2430) | ||
936 | * CLOCKS: | ||
937 | * MDM_OSC_CLK | ||
938 | * MDM_ICLK | ||
939 | */ | ||
940 | static struct clk mdm_ick = { /* used both as a ick and fck */ | ||
941 | .name = "mdm_ick", | ||
942 | .parent = &core_ck, | ||
943 | .flags = CLOCK_IN_OMAP243X | RATE_CKCTL | CM_MODEM_SEL1 | | ||
944 | DELAYED_APP | CONFIG_PARTICIPANT, | ||
945 | .rate_offset = 0, | ||
946 | .enable_reg = (void __iomem *)&CM_ICLKEN_MDM, | ||
947 | .enable_bit = 0, | ||
948 | .recalc = &omap2_clksel_recalc, | ||
949 | }; | ||
950 | |||
951 | static struct clk mdm_osc_ck = { | ||
952 | .name = "mdm_osc_ck", | ||
953 | .rate = 26000000, | ||
954 | .parent = &osc_ck, | ||
955 | .flags = CLOCK_IN_OMAP243X | RATE_FIXED, | ||
956 | .enable_reg = (void __iomem *)&CM_FCLKEN_MDM, | ||
957 | .enable_bit = 1, | ||
958 | .recalc = &omap2_followparent_recalc, | ||
959 | }; | ||
960 | |||
961 | /* | ||
962 | * L4 clock management domain | ||
963 | * | ||
964 | * This domain contains lots of interface clocks from the L4 interface, some | ||
965 | * functional clocks. Fixed APLL functional source clocks are managed in | ||
966 | * this domain. | ||
967 | */ | ||
968 | static struct clk l4_ck = { /* used both as an ick and fck */ | ||
969 | .name = "l4_ck", | ||
970 | .parent = &core_l3_ck, | ||
971 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
972 | RATE_CKCTL | ALWAYS_ENABLED | CM_CORE_SEL1 | | ||
973 | DELAYED_APP | RATE_PROPAGATES, | ||
974 | .rate_offset = 5, | ||
975 | .recalc = &omap2_clksel_recalc, | ||
976 | }; | ||
977 | |||
978 | static struct clk ssi_l4_ick = { | ||
979 | .name = "ssi_l4_ick", | ||
980 | .parent = &l4_ck, | ||
981 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | RATE_CKCTL, | ||
982 | .enable_reg = (void __iomem *)&CM_ICLKEN2_CORE, /* bit 1 */ | ||
983 | .enable_bit = 1, | ||
984 | .recalc = &omap2_followparent_recalc, | ||
985 | }; | ||
986 | |||
987 | /* | ||
988 | * DSS clock domain | ||
989 | * CLOCKs: | ||
990 | * DSS_L4_ICLK, DSS_L3_ICLK, | ||
991 | * DSS_CLK1, DSS_CLK2, DSS_54MHz_CLK | ||
992 | * | ||
993 | * DSS is both initiator and target. | ||
994 | */ | ||
995 | static struct clk dss_ick = { /* Enables both L3,L4 ICLK's */ | ||
996 | .name = "dss_ick", | ||
997 | .parent = &l4_ck, /* really both l3 and l4 */ | ||
998 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | RATE_CKCTL, | ||
999 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, | ||
1000 | .enable_bit = 0, | ||
1001 | .recalc = &omap2_followparent_recalc, | ||
1002 | }; | ||
1003 | |||
1004 | static struct clk dss1_fck = { | ||
1005 | .name = "dss1_fck", | ||
1006 | .parent = &core_ck, /* Core or sys */ | ||
1007 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
1008 | RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP, | ||
1009 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1010 | .enable_bit = 0, | ||
1011 | .rate_offset = 8, | ||
1012 | .src_offset = 8, | ||
1013 | .recalc = &omap2_clksel_recalc, | ||
1014 | }; | ||
1015 | |||
1016 | static struct clk dss2_fck = { /* Alt clk used in power management */ | ||
1017 | .name = "dss2_fck", | ||
1018 | .parent = &sys_ck, /* fixed at sys_ck or 48MHz */ | ||
1019 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
1020 | RATE_CKCTL | CM_CORE_SEL1 | RATE_FIXED, | ||
1021 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1022 | .enable_bit = 1, | ||
1023 | .src_offset = 13, | ||
1024 | .recalc = &omap2_followparent_recalc, | ||
1025 | }; | ||
1026 | |||
1027 | static struct clk dss_54m_fck = { /* Alt clk used in power management */ | ||
1028 | .name = "dss_54m_fck", /* 54m tv clk */ | ||
1029 | .parent = &func_54m_ck, | ||
1030 | .rate = 54000000, | ||
1031 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
1032 | RATE_FIXED | RATE_PROPAGATES, | ||
1033 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1034 | .enable_bit = 2, | ||
1035 | .recalc = &omap2_propagate_rate, | ||
1036 | }; | ||
1037 | |||
1038 | /* | ||
1039 | * CORE power domain ICLK & FCLK defines. | ||
1040 | * Many of the these can have more than one possible parent. Entries | ||
1041 | * here will likely have an L4 interface parent, and may have multiple | ||
1042 | * functional clock parents. | ||
1043 | */ | ||
1044 | static struct clk gpt1_ick = { | ||
1045 | .name = "gpt1_ick", | ||
1046 | .parent = &l4_ck, | ||
1047 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1048 | .enable_reg = (void __iomem *)&CM_ICLKEN_WKUP, /* Bit4 */ | ||
1049 | .enable_bit = 0, | ||
1050 | .recalc = &omap2_followparent_recalc, | ||
1051 | }; | ||
1052 | |||
1053 | static struct clk gpt1_fck = { | ||
1054 | .name = "gpt1_fck", | ||
1055 | .parent = &func_32k_ck, | ||
1056 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
1057 | CM_WKUP_SEL1, | ||
1058 | .enable_reg = (void __iomem *)&CM_FCLKEN_WKUP, | ||
1059 | .enable_bit = 0, | ||
1060 | .src_offset = 0, | ||
1061 | .recalc = &omap2_followparent_recalc, | ||
1062 | }; | ||
1063 | |||
1064 | static struct clk gpt2_ick = { | ||
1065 | .name = "gpt2_ick", | ||
1066 | .parent = &l4_ck, | ||
1067 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1068 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, /* bit4 */ | ||
1069 | .enable_bit = 0, | ||
1070 | .recalc = &omap2_followparent_recalc, | ||
1071 | }; | ||
1072 | |||
1073 | static struct clk gpt2_fck = { | ||
1074 | .name = "gpt2_fck", | ||
1075 | .parent = &func_32k_ck, | ||
1076 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
1077 | CM_CORE_SEL2, | ||
1078 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1079 | .enable_bit = 4, | ||
1080 | .src_offset = 2, | ||
1081 | .recalc = &omap2_followparent_recalc, | ||
1082 | }; | ||
1083 | |||
1084 | static struct clk gpt3_ick = { | ||
1085 | .name = "gpt3_ick", | ||
1086 | .parent = &l4_ck, | ||
1087 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1088 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, /* Bit5 */ | ||
1089 | .enable_bit = 5, | ||
1090 | .recalc = &omap2_followparent_recalc, | ||
1091 | }; | ||
1092 | |||
1093 | static struct clk gpt3_fck = { | ||
1094 | .name = "gpt3_fck", | ||
1095 | .parent = &func_32k_ck, | ||
1096 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
1097 | CM_CORE_SEL2, | ||
1098 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1099 | .enable_bit = 5, | ||
1100 | .src_offset = 4, | ||
1101 | .recalc = &omap2_followparent_recalc, | ||
1102 | }; | ||
1103 | |||
1104 | static struct clk gpt4_ick = { | ||
1105 | .name = "gpt4_ick", | ||
1106 | .parent = &l4_ck, | ||
1107 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1108 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, /* Bit6 */ | ||
1109 | .enable_bit = 6, | ||
1110 | .recalc = &omap2_followparent_recalc, | ||
1111 | }; | ||
1112 | |||
1113 | static struct clk gpt4_fck = { | ||
1114 | .name = "gpt4_fck", | ||
1115 | .parent = &func_32k_ck, | ||
1116 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
1117 | CM_CORE_SEL2, | ||
1118 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1119 | .enable_bit = 6, | ||
1120 | .src_offset = 6, | ||
1121 | .recalc = &omap2_followparent_recalc, | ||
1122 | }; | ||
1123 | |||
1124 | static struct clk gpt5_ick = { | ||
1125 | .name = "gpt5_ick", | ||
1126 | .parent = &l4_ck, | ||
1127 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1128 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, /* Bit7 */ | ||
1129 | .enable_bit = 7, | ||
1130 | .recalc = &omap2_followparent_recalc, | ||
1131 | }; | ||
1132 | |||
1133 | static struct clk gpt5_fck = { | ||
1134 | .name = "gpt5_fck", | ||
1135 | .parent = &func_32k_ck, | ||
1136 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
1137 | CM_CORE_SEL2, | ||
1138 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1139 | .enable_bit = 7, | ||
1140 | .src_offset = 8, | ||
1141 | .recalc = &omap2_followparent_recalc, | ||
1142 | }; | ||
1143 | |||
1144 | static struct clk gpt6_ick = { | ||
1145 | .name = "gpt6_ick", | ||
1146 | .parent = &l4_ck, | ||
1147 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1148 | .enable_bit = 8, | ||
1149 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, /* bit8 */ | ||
1150 | .recalc = &omap2_followparent_recalc, | ||
1151 | }; | ||
1152 | |||
1153 | static struct clk gpt6_fck = { | ||
1154 | .name = "gpt6_fck", | ||
1155 | .parent = &func_32k_ck, | ||
1156 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
1157 | CM_CORE_SEL2, | ||
1158 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1159 | .enable_bit = 8, | ||
1160 | .src_offset = 10, | ||
1161 | .recalc = &omap2_followparent_recalc, | ||
1162 | }; | ||
1163 | |||
1164 | static struct clk gpt7_ick = { | ||
1165 | .name = "gpt7_ick", | ||
1166 | .parent = &l4_ck, | ||
1167 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1168 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, /* bit9 */ | ||
1169 | .enable_bit = 9, | ||
1170 | .recalc = &omap2_followparent_recalc, | ||
1171 | }; | ||
1172 | |||
1173 | static struct clk gpt7_fck = { | ||
1174 | .name = "gpt7_fck", | ||
1175 | .parent = &func_32k_ck, | ||
1176 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
1177 | CM_CORE_SEL2, | ||
1178 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1179 | .enable_bit = 9, | ||
1180 | .src_offset = 12, | ||
1181 | .recalc = &omap2_followparent_recalc, | ||
1182 | }; | ||
1183 | |||
1184 | static struct clk gpt8_ick = { | ||
1185 | .name = "gpt8_ick", | ||
1186 | .parent = &l4_ck, | ||
1187 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1188 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, /* bit10 */ | ||
1189 | .enable_bit = 10, | ||
1190 | .recalc = &omap2_followparent_recalc, | ||
1191 | }; | ||
1192 | |||
1193 | static struct clk gpt8_fck = { | ||
1194 | .name = "gpt8_fck", | ||
1195 | .parent = &func_32k_ck, | ||
1196 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
1197 | CM_CORE_SEL2, | ||
1198 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1199 | .enable_bit = 10, | ||
1200 | .src_offset = 14, | ||
1201 | .recalc = &omap2_followparent_recalc, | ||
1202 | }; | ||
1203 | |||
1204 | static struct clk gpt9_ick = { | ||
1205 | .name = "gpt9_ick", | ||
1206 | .parent = &l4_ck, | ||
1207 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1208 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, | ||
1209 | .enable_bit = 11, | ||
1210 | .recalc = &omap2_followparent_recalc, | ||
1211 | }; | ||
1212 | |||
1213 | static struct clk gpt9_fck = { | ||
1214 | .name = "gpt9_fck", | ||
1215 | .parent = &func_32k_ck, | ||
1216 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
1217 | CM_CORE_SEL2, | ||
1218 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1219 | .enable_bit = 11, | ||
1220 | .src_offset = 16, | ||
1221 | .recalc = &omap2_followparent_recalc, | ||
1222 | }; | ||
1223 | |||
1224 | static struct clk gpt10_ick = { | ||
1225 | .name = "gpt10_ick", | ||
1226 | .parent = &l4_ck, | ||
1227 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1228 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, | ||
1229 | .enable_bit = 12, | ||
1230 | .recalc = &omap2_followparent_recalc, | ||
1231 | }; | ||
1232 | |||
1233 | static struct clk gpt10_fck = { | ||
1234 | .name = "gpt10_fck", | ||
1235 | .parent = &func_32k_ck, | ||
1236 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
1237 | CM_CORE_SEL2, | ||
1238 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1239 | .enable_bit = 12, | ||
1240 | .src_offset = 18, | ||
1241 | .recalc = &omap2_followparent_recalc, | ||
1242 | }; | ||
1243 | |||
1244 | static struct clk gpt11_ick = { | ||
1245 | .name = "gpt11_ick", | ||
1246 | .parent = &l4_ck, | ||
1247 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1248 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, | ||
1249 | .enable_bit = 13, | ||
1250 | .recalc = &omap2_followparent_recalc, | ||
1251 | }; | ||
1252 | |||
1253 | static struct clk gpt11_fck = { | ||
1254 | .name = "gpt11_fck", | ||
1255 | .parent = &func_32k_ck, | ||
1256 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
1257 | CM_CORE_SEL2, | ||
1258 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1259 | .enable_bit = 13, | ||
1260 | .src_offset = 20, | ||
1261 | .recalc = &omap2_followparent_recalc, | ||
1262 | }; | ||
1263 | |||
1264 | static struct clk gpt12_ick = { | ||
1265 | .name = "gpt12_ick", | ||
1266 | .parent = &l4_ck, | ||
1267 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1268 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, /* bit14 */ | ||
1269 | .enable_bit = 14, | ||
1270 | .recalc = &omap2_followparent_recalc, | ||
1271 | }; | ||
1272 | |||
1273 | static struct clk gpt12_fck = { | ||
1274 | .name = "gpt12_fck", | ||
1275 | .parent = &func_32k_ck, | ||
1276 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
1277 | CM_CORE_SEL2, | ||
1278 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1279 | .enable_bit = 14, | ||
1280 | .src_offset = 22, | ||
1281 | .recalc = &omap2_followparent_recalc, | ||
1282 | }; | ||
1283 | |||
1284 | static struct clk mcbsp1_ick = { | ||
1285 | .name = "mcbsp1_ick", | ||
1286 | .parent = &l4_ck, | ||
1287 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1288 | .enable_bit = 15, | ||
1289 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, /* bit16 */ | ||
1290 | .recalc = &omap2_followparent_recalc, | ||
1291 | }; | ||
1292 | |||
1293 | static struct clk mcbsp1_fck = { | ||
1294 | .name = "mcbsp1_fck", | ||
1295 | .parent = &func_96m_ck, | ||
1296 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1297 | .enable_bit = 15, | ||
1298 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1299 | .recalc = &omap2_followparent_recalc, | ||
1300 | }; | ||
1301 | |||
1302 | static struct clk mcbsp2_ick = { | ||
1303 | .name = "mcbsp2_ick", | ||
1304 | .parent = &l4_ck, | ||
1305 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1306 | .enable_bit = 16, | ||
1307 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, | ||
1308 | .recalc = &omap2_followparent_recalc, | ||
1309 | }; | ||
1310 | |||
1311 | static struct clk mcbsp2_fck = { | ||
1312 | .name = "mcbsp2_fck", | ||
1313 | .parent = &func_96m_ck, | ||
1314 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1315 | .enable_bit = 16, | ||
1316 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1317 | .recalc = &omap2_followparent_recalc, | ||
1318 | }; | ||
1319 | |||
1320 | static struct clk mcbsp3_ick = { | ||
1321 | .name = "mcbsp3_ick", | ||
1322 | .parent = &l4_ck, | ||
1323 | .flags = CLOCK_IN_OMAP243X, | ||
1324 | .enable_reg = (void __iomem *)&CM_ICLKEN2_CORE, | ||
1325 | .enable_bit = 3, | ||
1326 | .recalc = &omap2_followparent_recalc, | ||
1327 | }; | ||
1328 | |||
1329 | static struct clk mcbsp3_fck = { | ||
1330 | .name = "mcbsp3_fck", | ||
1331 | .parent = &func_96m_ck, | ||
1332 | .flags = CLOCK_IN_OMAP243X, | ||
1333 | .enable_reg = (void __iomem *)&CM_FCLKEN2_CORE, | ||
1334 | .enable_bit = 3, | ||
1335 | .recalc = &omap2_followparent_recalc, | ||
1336 | }; | ||
1337 | |||
1338 | static struct clk mcbsp4_ick = { | ||
1339 | .name = "mcbsp4_ick", | ||
1340 | .parent = &l4_ck, | ||
1341 | .flags = CLOCK_IN_OMAP243X, | ||
1342 | .enable_reg = (void __iomem *)&CM_ICLKEN2_CORE, | ||
1343 | .enable_bit = 4, | ||
1344 | .recalc = &omap2_followparent_recalc, | ||
1345 | }; | ||
1346 | |||
1347 | static struct clk mcbsp4_fck = { | ||
1348 | .name = "mcbsp4_fck", | ||
1349 | .parent = &func_96m_ck, | ||
1350 | .flags = CLOCK_IN_OMAP243X, | ||
1351 | .enable_reg = (void __iomem *)&CM_FCLKEN2_CORE, | ||
1352 | .enable_bit = 4, | ||
1353 | .recalc = &omap2_followparent_recalc, | ||
1354 | }; | ||
1355 | |||
1356 | static struct clk mcbsp5_ick = { | ||
1357 | .name = "mcbsp5_ick", | ||
1358 | .parent = &l4_ck, | ||
1359 | .flags = CLOCK_IN_OMAP243X, | ||
1360 | .enable_reg = (void __iomem *)&CM_ICLKEN2_CORE, | ||
1361 | .enable_bit = 5, | ||
1362 | .recalc = &omap2_followparent_recalc, | ||
1363 | }; | ||
1364 | |||
1365 | static struct clk mcbsp5_fck = { | ||
1366 | .name = "mcbsp5_fck", | ||
1367 | .parent = &func_96m_ck, | ||
1368 | .flags = CLOCK_IN_OMAP243X, | ||
1369 | .enable_reg = (void __iomem *)&CM_FCLKEN2_CORE, | ||
1370 | .enable_bit = 5, | ||
1371 | .recalc = &omap2_followparent_recalc, | ||
1372 | }; | ||
1373 | |||
1374 | static struct clk mcspi1_ick = { | ||
1375 | .name = "mcspi1_ick", | ||
1376 | .parent = &l4_ck, | ||
1377 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1378 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, | ||
1379 | .enable_bit = 17, | ||
1380 | .recalc = &omap2_followparent_recalc, | ||
1381 | }; | ||
1382 | |||
1383 | static struct clk mcspi1_fck = { | ||
1384 | .name = "mcspi1_fck", | ||
1385 | .parent = &func_48m_ck, | ||
1386 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1387 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1388 | .enable_bit = 17, | ||
1389 | .recalc = &omap2_followparent_recalc, | ||
1390 | }; | ||
1391 | |||
1392 | static struct clk mcspi2_ick = { | ||
1393 | .name = "mcspi2_ick", | ||
1394 | .parent = &l4_ck, | ||
1395 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1396 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, | ||
1397 | .enable_bit = 18, | ||
1398 | .recalc = &omap2_followparent_recalc, | ||
1399 | }; | ||
1400 | |||
1401 | static struct clk mcspi2_fck = { | ||
1402 | .name = "mcspi2_fck", | ||
1403 | .parent = &func_48m_ck, | ||
1404 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1405 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1406 | .enable_bit = 18, | ||
1407 | .recalc = &omap2_followparent_recalc, | ||
1408 | }; | ||
1409 | |||
1410 | static struct clk mcspi3_ick = { | ||
1411 | .name = "mcspi3_ick", | ||
1412 | .parent = &l4_ck, | ||
1413 | .flags = CLOCK_IN_OMAP243X, | ||
1414 | .enable_reg = (void __iomem *)&CM_ICLKEN2_CORE, | ||
1415 | .enable_bit = 9, | ||
1416 | .recalc = &omap2_followparent_recalc, | ||
1417 | }; | ||
1418 | |||
1419 | static struct clk mcspi3_fck = { | ||
1420 | .name = "mcspi3_fck", | ||
1421 | .parent = &func_48m_ck, | ||
1422 | .flags = CLOCK_IN_OMAP243X, | ||
1423 | .enable_reg = (void __iomem *)&CM_FCLKEN2_CORE, | ||
1424 | .enable_bit = 9, | ||
1425 | .recalc = &omap2_followparent_recalc, | ||
1426 | }; | ||
1427 | |||
1428 | static struct clk uart1_ick = { | ||
1429 | .name = "uart1_ick", | ||
1430 | .parent = &l4_ck, | ||
1431 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1432 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, | ||
1433 | .enable_bit = 21, | ||
1434 | .recalc = &omap2_followparent_recalc, | ||
1435 | }; | ||
1436 | |||
1437 | static struct clk uart1_fck = { | ||
1438 | .name = "uart1_fck", | ||
1439 | .parent = &func_48m_ck, | ||
1440 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1441 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1442 | .enable_bit = 21, | ||
1443 | .recalc = &omap2_followparent_recalc, | ||
1444 | }; | ||
1445 | |||
1446 | static struct clk uart2_ick = { | ||
1447 | .name = "uart2_ick", | ||
1448 | .parent = &l4_ck, | ||
1449 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1450 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, | ||
1451 | .enable_bit = 22, | ||
1452 | .recalc = &omap2_followparent_recalc, | ||
1453 | }; | ||
1454 | |||
1455 | static struct clk uart2_fck = { | ||
1456 | .name = "uart2_fck", | ||
1457 | .parent = &func_48m_ck, | ||
1458 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1459 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1460 | .enable_bit = 22, | ||
1461 | .recalc = &omap2_followparent_recalc, | ||
1462 | }; | ||
1463 | |||
1464 | static struct clk uart3_ick = { | ||
1465 | .name = "uart3_ick", | ||
1466 | .parent = &l4_ck, | ||
1467 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1468 | .enable_reg = (void __iomem *)&CM_ICLKEN2_CORE, | ||
1469 | .enable_bit = 2, | ||
1470 | .recalc = &omap2_followparent_recalc, | ||
1471 | }; | ||
1472 | |||
1473 | static struct clk uart3_fck = { | ||
1474 | .name = "uart3_fck", | ||
1475 | .parent = &func_48m_ck, | ||
1476 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1477 | .enable_reg = (void __iomem *)&CM_FCLKEN2_CORE, | ||
1478 | .enable_bit = 2, | ||
1479 | .recalc = &omap2_followparent_recalc, | ||
1480 | }; | ||
1481 | |||
1482 | static struct clk gpios_ick = { | ||
1483 | .name = "gpios_ick", | ||
1484 | .parent = &l4_ck, | ||
1485 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1486 | .enable_reg = (void __iomem *)&CM_ICLKEN_WKUP, | ||
1487 | .enable_bit = 2, | ||
1488 | .recalc = &omap2_followparent_recalc, | ||
1489 | }; | ||
1490 | |||
1491 | static struct clk gpios_fck = { | ||
1492 | .name = "gpios_fck", | ||
1493 | .parent = &func_32k_ck, | ||
1494 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1495 | .enable_reg = (void __iomem *)&CM_FCLKEN_WKUP, | ||
1496 | .enable_bit = 2, | ||
1497 | .recalc = &omap2_followparent_recalc, | ||
1498 | }; | ||
1499 | |||
1500 | static struct clk mpu_wdt_ick = { | ||
1501 | .name = "mpu_wdt_ick", | ||
1502 | .parent = &l4_ck, | ||
1503 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1504 | .enable_reg = (void __iomem *)&CM_ICLKEN_WKUP, | ||
1505 | .enable_bit = 3, | ||
1506 | .recalc = &omap2_followparent_recalc, | ||
1507 | }; | ||
1508 | |||
1509 | static struct clk mpu_wdt_fck = { | ||
1510 | .name = "mpu_wdt_fck", | ||
1511 | .parent = &func_32k_ck, | ||
1512 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1513 | .enable_reg = (void __iomem *)&CM_FCLKEN_WKUP, | ||
1514 | .enable_bit = 3, | ||
1515 | .recalc = &omap2_followparent_recalc, | ||
1516 | }; | ||
1517 | |||
1518 | static struct clk sync_32k_ick = { | ||
1519 | .name = "sync_32k_ick", | ||
1520 | .parent = &l4_ck, | ||
1521 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1522 | .enable_reg = (void __iomem *)&CM_ICLKEN_WKUP, | ||
1523 | .enable_bit = 1, | ||
1524 | .recalc = &omap2_followparent_recalc, | ||
1525 | }; | ||
1526 | static struct clk wdt1_ick = { | ||
1527 | .name = "wdt1_ick", | ||
1528 | .parent = &l4_ck, | ||
1529 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1530 | .enable_reg = (void __iomem *)&CM_ICLKEN_WKUP, | ||
1531 | .enable_bit = 4, | ||
1532 | .recalc = &omap2_followparent_recalc, | ||
1533 | }; | ||
1534 | static struct clk omapctrl_ick = { | ||
1535 | .name = "omapctrl_ick", | ||
1536 | .parent = &l4_ck, | ||
1537 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1538 | .enable_reg = (void __iomem *)&CM_ICLKEN_WKUP, | ||
1539 | .enable_bit = 5, | ||
1540 | .recalc = &omap2_followparent_recalc, | ||
1541 | }; | ||
1542 | static struct clk icr_ick = { | ||
1543 | .name = "icr_ick", | ||
1544 | .parent = &l4_ck, | ||
1545 | .flags = CLOCK_IN_OMAP243X, | ||
1546 | .enable_reg = (void __iomem *)&CM_ICLKEN_WKUP, | ||
1547 | .enable_bit = 6, | ||
1548 | .recalc = &omap2_followparent_recalc, | ||
1549 | }; | ||
1550 | |||
1551 | static struct clk cam_ick = { | ||
1552 | .name = "cam_ick", | ||
1553 | .parent = &l4_ck, | ||
1554 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1555 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, | ||
1556 | .enable_bit = 31, | ||
1557 | .recalc = &omap2_followparent_recalc, | ||
1558 | }; | ||
1559 | |||
1560 | static struct clk cam_fck = { | ||
1561 | .name = "cam_fck", | ||
1562 | .parent = &func_96m_ck, | ||
1563 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1564 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1565 | .enable_bit = 31, | ||
1566 | .recalc = &omap2_followparent_recalc, | ||
1567 | }; | ||
1568 | |||
1569 | static struct clk mailboxes_ick = { | ||
1570 | .name = "mailboxes_ick", | ||
1571 | .parent = &l4_ck, | ||
1572 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1573 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, | ||
1574 | .enable_bit = 30, | ||
1575 | .recalc = &omap2_followparent_recalc, | ||
1576 | }; | ||
1577 | |||
1578 | static struct clk wdt4_ick = { | ||
1579 | .name = "wdt4_ick", | ||
1580 | .parent = &l4_ck, | ||
1581 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1582 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, | ||
1583 | .enable_bit = 29, | ||
1584 | .recalc = &omap2_followparent_recalc, | ||
1585 | }; | ||
1586 | |||
1587 | static struct clk wdt4_fck = { | ||
1588 | .name = "wdt4_fck", | ||
1589 | .parent = &func_32k_ck, | ||
1590 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1591 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1592 | .enable_bit = 29, | ||
1593 | .recalc = &omap2_followparent_recalc, | ||
1594 | }; | ||
1595 | |||
1596 | static struct clk wdt3_ick = { | ||
1597 | .name = "wdt3_ick", | ||
1598 | .parent = &l4_ck, | ||
1599 | .flags = CLOCK_IN_OMAP242X, | ||
1600 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, | ||
1601 | .enable_bit = 28, | ||
1602 | .recalc = &omap2_followparent_recalc, | ||
1603 | }; | ||
1604 | |||
1605 | static struct clk wdt3_fck = { | ||
1606 | .name = "wdt3_fck", | ||
1607 | .parent = &func_32k_ck, | ||
1608 | .flags = CLOCK_IN_OMAP242X, | ||
1609 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1610 | .enable_bit = 28, | ||
1611 | .recalc = &omap2_followparent_recalc, | ||
1612 | }; | ||
1613 | |||
1614 | static struct clk mspro_ick = { | ||
1615 | .name = "mspro_ick", | ||
1616 | .parent = &l4_ck, | ||
1617 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1618 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, | ||
1619 | .enable_bit = 27, | ||
1620 | .recalc = &omap2_followparent_recalc, | ||
1621 | }; | ||
1622 | |||
1623 | static struct clk mspro_fck = { | ||
1624 | .name = "mspro_fck", | ||
1625 | .parent = &func_96m_ck, | ||
1626 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1627 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1628 | .enable_bit = 27, | ||
1629 | .recalc = &omap2_followparent_recalc, | ||
1630 | }; | ||
1631 | |||
1632 | static struct clk mmc_ick = { | ||
1633 | .name = "mmc_ick", | ||
1634 | .parent = &l4_ck, | ||
1635 | .flags = CLOCK_IN_OMAP242X, | ||
1636 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, | ||
1637 | .enable_bit = 26, | ||
1638 | .recalc = &omap2_followparent_recalc, | ||
1639 | }; | ||
1640 | |||
1641 | static struct clk mmc_fck = { | ||
1642 | .name = "mmc_fck", | ||
1643 | .parent = &func_96m_ck, | ||
1644 | .flags = CLOCK_IN_OMAP242X, | ||
1645 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1646 | .enable_bit = 26, | ||
1647 | .recalc = &omap2_followparent_recalc, | ||
1648 | }; | ||
1649 | |||
1650 | static struct clk fac_ick = { | ||
1651 | .name = "fac_ick", | ||
1652 | .parent = &l4_ck, | ||
1653 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1654 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, | ||
1655 | .enable_bit = 25, | ||
1656 | .recalc = &omap2_followparent_recalc, | ||
1657 | }; | ||
1658 | |||
1659 | static struct clk fac_fck = { | ||
1660 | .name = "fac_fck", | ||
1661 | .parent = &func_12m_ck, | ||
1662 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1663 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1664 | .enable_bit = 25, | ||
1665 | .recalc = &omap2_followparent_recalc, | ||
1666 | }; | ||
1667 | |||
1668 | static struct clk eac_ick = { | ||
1669 | .name = "eac_ick", | ||
1670 | .parent = &l4_ck, | ||
1671 | .flags = CLOCK_IN_OMAP242X, | ||
1672 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, | ||
1673 | .enable_bit = 24, | ||
1674 | .recalc = &omap2_followparent_recalc, | ||
1675 | }; | ||
1676 | |||
1677 | static struct clk eac_fck = { | ||
1678 | .name = "eac_fck", | ||
1679 | .parent = &func_96m_ck, | ||
1680 | .flags = CLOCK_IN_OMAP242X, | ||
1681 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1682 | .enable_bit = 24, | ||
1683 | .recalc = &omap2_followparent_recalc, | ||
1684 | }; | ||
1685 | |||
1686 | static struct clk hdq_ick = { | ||
1687 | .name = "hdq_ick", | ||
1688 | .parent = &l4_ck, | ||
1689 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1690 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, | ||
1691 | .enable_bit = 23, | ||
1692 | .recalc = &omap2_followparent_recalc, | ||
1693 | }; | ||
1694 | |||
1695 | static struct clk hdq_fck = { | ||
1696 | .name = "hdq_fck", | ||
1697 | .parent = &func_12m_ck, | ||
1698 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1699 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1700 | .enable_bit = 23, | ||
1701 | .recalc = &omap2_followparent_recalc, | ||
1702 | }; | ||
1703 | |||
1704 | static struct clk i2c2_ick = { | ||
1705 | .name = "i2c2_ick", | ||
1706 | .parent = &l4_ck, | ||
1707 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1708 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, | ||
1709 | .enable_bit = 20, | ||
1710 | .recalc = &omap2_followparent_recalc, | ||
1711 | }; | ||
1712 | |||
1713 | static struct clk i2c2_fck = { | ||
1714 | .name = "i2c2_fck", | ||
1715 | .parent = &func_12m_ck, | ||
1716 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1717 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1718 | .enable_bit = 20, | ||
1719 | .recalc = &omap2_followparent_recalc, | ||
1720 | }; | ||
1721 | |||
1722 | static struct clk i2chs2_fck = { | ||
1723 | .name = "i2chs2_fck", | ||
1724 | .parent = &func_96m_ck, | ||
1725 | .flags = CLOCK_IN_OMAP243X, | ||
1726 | .enable_reg = (void __iomem *)&CM_FCLKEN2_CORE, | ||
1727 | .enable_bit = 20, | ||
1728 | .recalc = &omap2_followparent_recalc, | ||
1729 | }; | ||
1730 | |||
1731 | static struct clk i2c1_ick = { | ||
1732 | .name = "i2c1_ick", | ||
1733 | .parent = &l4_ck, | ||
1734 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1735 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, | ||
1736 | .enable_bit = 19, | ||
1737 | .recalc = &omap2_followparent_recalc, | ||
1738 | }; | ||
1739 | |||
1740 | static struct clk i2c1_fck = { | ||
1741 | .name = "i2c1_fck", | ||
1742 | .parent = &func_12m_ck, | ||
1743 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, | ||
1744 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1745 | .enable_bit = 19, | ||
1746 | .recalc = &omap2_followparent_recalc, | ||
1747 | }; | ||
1748 | |||
1749 | static struct clk i2chs1_fck = { | ||
1750 | .name = "i2chs1_fck", | ||
1751 | .parent = &func_96m_ck, | ||
1752 | .flags = CLOCK_IN_OMAP243X, | ||
1753 | .enable_reg = (void __iomem *)&CM_FCLKEN2_CORE, | ||
1754 | .enable_bit = 19, | ||
1755 | .recalc = &omap2_followparent_recalc, | ||
1756 | }; | ||
1757 | |||
1758 | static struct clk vlynq_ick = { | ||
1759 | .name = "vlynq_ick", | ||
1760 | .parent = &core_l3_ck, | ||
1761 | .flags = CLOCK_IN_OMAP242X, | ||
1762 | .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, | ||
1763 | .enable_bit = 3, | ||
1764 | .recalc = &omap2_followparent_recalc, | ||
1765 | }; | ||
1766 | |||
1767 | static struct clk vlynq_fck = { | ||
1768 | .name = "vlynq_fck", | ||
1769 | .parent = &func_96m_ck, | ||
1770 | .flags = CLOCK_IN_OMAP242X | RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP, | ||
1771 | .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, | ||
1772 | .enable_bit = 3, | ||
1773 | .src_offset = 15, | ||
1774 | .recalc = &omap2_followparent_recalc, | ||
1775 | }; | ||
1776 | |||
1777 | static struct clk sdrc_ick = { | ||
1778 | .name = "sdrc_ick", | ||
1779 | .parent = &l4_ck, | ||
1780 | .flags = CLOCK_IN_OMAP243X, | ||
1781 | .enable_reg = (void __iomem *)&CM_ICLKEN3_CORE, | ||
1782 | .enable_bit = 2, | ||
1783 | .recalc = &omap2_followparent_recalc, | ||
1784 | }; | ||
1785 | |||
1786 | static struct clk des_ick = { | ||
1787 | .name = "des_ick", | ||
1788 | .parent = &l4_ck, | ||
1789 | .flags = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X, | ||
1790 | .enable_reg = (void __iomem *)&CM_ICLKEN4_CORE, | ||
1791 | .enable_bit = 0, | ||
1792 | .recalc = &omap2_followparent_recalc, | ||
1793 | }; | ||
1794 | |||
1795 | static struct clk sha_ick = { | ||
1796 | .name = "sha_ick", | ||
1797 | .parent = &l4_ck, | ||
1798 | .flags = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X, | ||
1799 | .enable_reg = (void __iomem *)&CM_ICLKEN4_CORE, | ||
1800 | .enable_bit = 1, | ||
1801 | .recalc = &omap2_followparent_recalc, | ||
1802 | }; | ||
1803 | |||
1804 | static struct clk rng_ick = { | ||
1805 | .name = "rng_ick", | ||
1806 | .parent = &l4_ck, | ||
1807 | .flags = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X, | ||
1808 | .enable_reg = (void __iomem *)&CM_ICLKEN4_CORE, | ||
1809 | .enable_bit = 2, | ||
1810 | .recalc = &omap2_followparent_recalc, | ||
1811 | }; | ||
1812 | |||
1813 | static struct clk aes_ick = { | ||
1814 | .name = "aes_ick", | ||
1815 | .parent = &l4_ck, | ||
1816 | .flags = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X, | ||
1817 | .enable_reg = (void __iomem *)&CM_ICLKEN4_CORE, | ||
1818 | .enable_bit = 3, | ||
1819 | .recalc = &omap2_followparent_recalc, | ||
1820 | }; | ||
1821 | |||
1822 | static struct clk pka_ick = { | ||
1823 | .name = "pka_ick", | ||
1824 | .parent = &l4_ck, | ||
1825 | .flags = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X, | ||
1826 | .enable_reg = (void __iomem *)&CM_ICLKEN4_CORE, | ||
1827 | .enable_bit = 4, | ||
1828 | .recalc = &omap2_followparent_recalc, | ||
1829 | }; | ||
1830 | |||
1831 | static struct clk usb_fck = { | ||
1832 | .name = "usb_fck", | ||
1833 | .parent = &func_48m_ck, | ||
1834 | .flags = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X, | ||
1835 | .enable_reg = (void __iomem *)&CM_FCLKEN2_CORE, | ||
1836 | .enable_bit = 0, | ||
1837 | .recalc = &omap2_followparent_recalc, | ||
1838 | }; | ||
1839 | |||
1840 | static struct clk usbhs_ick = { | ||
1841 | .name = "usbhs_ick", | ||
1842 | .parent = &l4_ck, | ||
1843 | .flags = CLOCK_IN_OMAP243X, | ||
1844 | .enable_reg = (void __iomem *)&CM_ICLKEN2_CORE, | ||
1845 | .enable_bit = 6, | ||
1846 | .recalc = &omap2_followparent_recalc, | ||
1847 | }; | ||
1848 | |||
1849 | static struct clk mmchs1_ick = { | ||
1850 | .name = "mmchs1_ick", | ||
1851 | .parent = &l4_ck, | ||
1852 | .flags = CLOCK_IN_OMAP243X, | ||
1853 | .enable_reg = (void __iomem *)&CM_ICLKEN2_CORE, | ||
1854 | .enable_bit = 7, | ||
1855 | .recalc = &omap2_followparent_recalc, | ||
1856 | }; | ||
1857 | |||
1858 | static struct clk mmchs1_fck = { | ||
1859 | .name = "mmchs1_fck", | ||
1860 | .parent = &func_96m_ck, | ||
1861 | .flags = CLOCK_IN_OMAP243X, | ||
1862 | .enable_reg = (void __iomem *)&CM_FCLKEN2_CORE, | ||
1863 | .enable_bit = 7, | ||
1864 | .recalc = &omap2_followparent_recalc, | ||
1865 | }; | ||
1866 | |||
1867 | static struct clk mmchs2_ick = { | ||
1868 | .name = "mmchs2_ick", | ||
1869 | .parent = &l4_ck, | ||
1870 | .flags = CLOCK_IN_OMAP243X, | ||
1871 | .enable_reg = (void __iomem *)&CM_ICLKEN2_CORE, | ||
1872 | .enable_bit = 8, | ||
1873 | .recalc = &omap2_followparent_recalc, | ||
1874 | }; | ||
1875 | |||
1876 | static struct clk mmchs2_fck = { | ||
1877 | .name = "mmchs2_fck", | ||
1878 | .parent = &func_96m_ck, | ||
1879 | .flags = CLOCK_IN_OMAP243X, | ||
1880 | .enable_reg = (void __iomem *)&CM_FCLKEN2_CORE, | ||
1881 | .enable_bit = 8, | ||
1882 | .recalc = &omap2_followparent_recalc, | ||
1883 | }; | ||
1884 | |||
1885 | static struct clk gpio5_ick = { | ||
1886 | .name = "gpio5_ick", | ||
1887 | .parent = &l4_ck, | ||
1888 | .flags = CLOCK_IN_OMAP243X, | ||
1889 | .enable_reg = (void __iomem *)&CM_ICLKEN2_CORE, | ||
1890 | .enable_bit = 10, | ||
1891 | .recalc = &omap2_followparent_recalc, | ||
1892 | }; | ||
1893 | |||
1894 | static struct clk gpio5_fck = { | ||
1895 | .name = "gpio5_fck", | ||
1896 | .parent = &func_32k_ck, | ||
1897 | .flags = CLOCK_IN_OMAP243X, | ||
1898 | .enable_reg = (void __iomem *)&CM_FCLKEN2_CORE, | ||
1899 | .enable_bit = 10, | ||
1900 | .recalc = &omap2_followparent_recalc, | ||
1901 | }; | ||
1902 | |||
1903 | static struct clk mdm_intc_ick = { | ||
1904 | .name = "mdm_intc_ick", | ||
1905 | .parent = &l4_ck, | ||
1906 | .flags = CLOCK_IN_OMAP243X, | ||
1907 | .enable_reg = (void __iomem *)&CM_ICLKEN2_CORE, | ||
1908 | .enable_bit = 11, | ||
1909 | .recalc = &omap2_followparent_recalc, | ||
1910 | }; | ||
1911 | |||
1912 | static struct clk mmchsdb1_fck = { | ||
1913 | .name = "mmchsdb1_fck", | ||
1914 | .parent = &func_32k_ck, | ||
1915 | .flags = CLOCK_IN_OMAP243X, | ||
1916 | .enable_reg = (void __iomem *)&CM_FCLKEN2_CORE, | ||
1917 | .enable_bit = 16, | ||
1918 | .recalc = &omap2_followparent_recalc, | ||
1919 | }; | ||
1920 | |||
1921 | static struct clk mmchsdb2_fck = { | ||
1922 | .name = "mmchsdb2_fck", | ||
1923 | .parent = &func_32k_ck, | ||
1924 | .flags = CLOCK_IN_OMAP243X, | ||
1925 | .enable_reg = (void __iomem *)&CM_FCLKEN2_CORE, | ||
1926 | .enable_bit = 17, | ||
1927 | .recalc = &omap2_followparent_recalc, | ||
1928 | }; | ||
1929 | |||
1930 | /* | ||
1931 | * This clock is a composite clock which does entire set changes then | ||
1932 | * forces a rebalance. It keys on the MPU speed, but it really could | ||
1933 | * be any key speed part of a set in the rate table. | ||
1934 | * | ||
1935 | * to really change a set, you need memory table sets which get changed | ||
1936 | * in sram, pre-notifiers & post notifiers, changing the top set, without | ||
1937 | * having low level display recalc's won't work... this is why dpm notifiers | ||
1938 | * work, isr's off, walk a list of clocks already _off_ and not messing with | ||
1939 | * the bus. | ||
1940 | * | ||
1941 | * This clock should have no parent. It embodies the entire upper level | ||
1942 | * active set. A parent will mess up some of the init also. | ||
1943 | */ | ||
1944 | static struct clk virt_prcm_set = { | ||
1945 | .name = "virt_prcm_set", | ||
1946 | .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | | ||
1947 | VIRTUAL_CLOCK | ALWAYS_ENABLED | DELAYED_APP, | ||
1948 | .parent = &mpu_ck, /* Indexed by mpu speed, no parent */ | ||
1949 | .recalc = &omap2_mpu_recalc, /* sets are keyed on mpu rate */ | ||
1950 | .set_rate = &omap2_select_table_rate, | ||
1951 | .round_rate = &omap2_round_to_table_rate, | ||
1952 | }; | ||
1953 | |||
1954 | static struct clk *onchip_clks[] = { | ||
1955 | /* external root sources */ | ||
1956 | &func_32k_ck, | ||
1957 | &osc_ck, | ||
1958 | &sys_ck, | ||
1959 | &alt_ck, | ||
1960 | /* internal analog sources */ | ||
1961 | &dpll_ck, | ||
1962 | &apll96_ck, | ||
1963 | &apll54_ck, | ||
1964 | /* internal prcm root sources */ | ||
1965 | &func_54m_ck, | ||
1966 | &core_ck, | ||
1967 | &sleep_ck, | ||
1968 | &func_96m_ck, | ||
1969 | &func_48m_ck, | ||
1970 | &func_12m_ck, | ||
1971 | &wdt1_osc_ck, | ||
1972 | &sys_clkout, | ||
1973 | &sys_clkout2, | ||
1974 | /* mpu domain clocks */ | ||
1975 | &mpu_ck, | ||
1976 | /* dsp domain clocks */ | ||
1977 | &iva2_1_fck, /* 2430 */ | ||
1978 | &iva2_1_ick, | ||
1979 | &dsp_ick, /* 2420 */ | ||
1980 | &dsp_fck, | ||
1981 | &iva1_ifck, | ||
1982 | &iva1_mpu_int_ifck, | ||
1983 | /* GFX domain clocks */ | ||
1984 | &gfx_3d_fck, | ||
1985 | &gfx_2d_fck, | ||
1986 | &gfx_ick, | ||
1987 | /* Modem domain clocks */ | ||
1988 | &mdm_ick, | ||
1989 | &mdm_osc_ck, | ||
1990 | /* DSS domain clocks */ | ||
1991 | &dss_ick, | ||
1992 | &dss1_fck, | ||
1993 | &dss2_fck, | ||
1994 | &dss_54m_fck, | ||
1995 | /* L3 domain clocks */ | ||
1996 | &core_l3_ck, | ||
1997 | &ssi_ssr_sst_fck, | ||
1998 | &usb_l4_ick, | ||
1999 | /* L4 domain clocks */ | ||
2000 | &l4_ck, /* used as both core_l4 and wu_l4 */ | ||
2001 | &ssi_l4_ick, | ||
2002 | /* virtual meta-group clock */ | ||
2003 | &virt_prcm_set, | ||
2004 | /* general l4 interface ck, multi-parent functional clk */ | ||
2005 | &gpt1_ick, | ||
2006 | &gpt1_fck, | ||
2007 | &gpt2_ick, | ||
2008 | &gpt2_fck, | ||
2009 | &gpt3_ick, | ||
2010 | &gpt3_fck, | ||
2011 | &gpt4_ick, | ||
2012 | &gpt4_fck, | ||
2013 | &gpt5_ick, | ||
2014 | &gpt5_fck, | ||
2015 | &gpt6_ick, | ||
2016 | &gpt6_fck, | ||
2017 | &gpt7_ick, | ||
2018 | &gpt7_fck, | ||
2019 | &gpt8_ick, | ||
2020 | &gpt8_fck, | ||
2021 | &gpt9_ick, | ||
2022 | &gpt9_fck, | ||
2023 | &gpt10_ick, | ||
2024 | &gpt10_fck, | ||
2025 | &gpt11_ick, | ||
2026 | &gpt11_fck, | ||
2027 | &gpt12_ick, | ||
2028 | &gpt12_fck, | ||
2029 | &mcbsp1_ick, | ||
2030 | &mcbsp1_fck, | ||
2031 | &mcbsp2_ick, | ||
2032 | &mcbsp2_fck, | ||
2033 | &mcbsp3_ick, | ||
2034 | &mcbsp3_fck, | ||
2035 | &mcbsp4_ick, | ||
2036 | &mcbsp4_fck, | ||
2037 | &mcbsp5_ick, | ||
2038 | &mcbsp5_fck, | ||
2039 | &mcspi1_ick, | ||
2040 | &mcspi1_fck, | ||
2041 | &mcspi2_ick, | ||
2042 | &mcspi2_fck, | ||
2043 | &mcspi3_ick, | ||
2044 | &mcspi3_fck, | ||
2045 | &uart1_ick, | ||
2046 | &uart1_fck, | ||
2047 | &uart2_ick, | ||
2048 | &uart2_fck, | ||
2049 | &uart3_ick, | ||
2050 | &uart3_fck, | ||
2051 | &gpios_ick, | ||
2052 | &gpios_fck, | ||
2053 | &mpu_wdt_ick, | ||
2054 | &mpu_wdt_fck, | ||
2055 | &sync_32k_ick, | ||
2056 | &wdt1_ick, | ||
2057 | &omapctrl_ick, | ||
2058 | &icr_ick, | ||
2059 | &cam_fck, | ||
2060 | &cam_ick, | ||
2061 | &mailboxes_ick, | ||
2062 | &wdt4_ick, | ||
2063 | &wdt4_fck, | ||
2064 | &wdt3_ick, | ||
2065 | &wdt3_fck, | ||
2066 | &mspro_ick, | ||
2067 | &mspro_fck, | ||
2068 | &mmc_ick, | ||
2069 | &mmc_fck, | ||
2070 | &fac_ick, | ||
2071 | &fac_fck, | ||
2072 | &eac_ick, | ||
2073 | &eac_fck, | ||
2074 | &hdq_ick, | ||
2075 | &hdq_fck, | ||
2076 | &i2c1_ick, | ||
2077 | &i2c1_fck, | ||
2078 | &i2chs1_fck, | ||
2079 | &i2c2_ick, | ||
2080 | &i2c2_fck, | ||
2081 | &i2chs2_fck, | ||
2082 | &vlynq_ick, | ||
2083 | &vlynq_fck, | ||
2084 | &sdrc_ick, | ||
2085 | &des_ick, | ||
2086 | &sha_ick, | ||
2087 | &rng_ick, | ||
2088 | &aes_ick, | ||
2089 | &pka_ick, | ||
2090 | &usb_fck, | ||
2091 | &usbhs_ick, | ||
2092 | &mmchs1_ick, | ||
2093 | &mmchs1_fck, | ||
2094 | &mmchs2_ick, | ||
2095 | &mmchs2_fck, | ||
2096 | &gpio5_ick, | ||
2097 | &gpio5_fck, | ||
2098 | &mdm_intc_ick, | ||
2099 | &mmchsdb1_fck, | ||
2100 | &mmchsdb2_fck, | ||
2101 | }; | ||
2102 | |||
2103 | #endif | ||
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c new file mode 100644 index 000000000000..7181edb89352 --- /dev/null +++ b/arch/arm/mach-omap2/devices.c | |||
@@ -0,0 +1,89 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-omap2/devices.c | ||
3 | * | ||
4 | * OMAP2 platform device setup/initialization | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | |||
18 | #include <asm/hardware.h> | ||
19 | #include <asm/io.h> | ||
20 | #include <asm/mach-types.h> | ||
21 | #include <asm/mach/map.h> | ||
22 | |||
23 | #include <asm/arch/tc.h> | ||
24 | #include <asm/arch/board.h> | ||
25 | #include <asm/arch/mux.h> | ||
26 | #include <asm/arch/gpio.h> | ||
27 | |||
28 | extern void omap_nop_release(struct device *dev); | ||
29 | |||
30 | /*-------------------------------------------------------------------------*/ | ||
31 | |||
32 | #if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE) | ||
33 | |||
34 | #define OMAP2_I2C_BASE2 0x48072000 | ||
35 | #define OMAP2_I2C_INT2 57 | ||
36 | |||
37 | static struct resource i2c_resources2[] = { | ||
38 | { | ||
39 | .start = OMAP2_I2C_BASE2, | ||
40 | .end = OMAP2_I2C_BASE2 + 0x3f, | ||
41 | .flags = IORESOURCE_MEM, | ||
42 | }, | ||
43 | { | ||
44 | .start = OMAP2_I2C_INT2, | ||
45 | .flags = IORESOURCE_IRQ, | ||
46 | }, | ||
47 | }; | ||
48 | |||
49 | static struct platform_device omap_i2c_device2 = { | ||
50 | .name = "i2c_omap", | ||
51 | .id = 2, | ||
52 | .dev = { | ||
53 | .release = omap_nop_release, | ||
54 | }, | ||
55 | .num_resources = ARRAY_SIZE(i2c_resources2), | ||
56 | .resource = i2c_resources2, | ||
57 | }; | ||
58 | |||
59 | /* See also arch/arm/plat-omap/devices.c for first I2C on 24xx */ | ||
60 | static void omap_init_i2c(void) | ||
61 | { | ||
62 | /* REVISIT: Second I2C not in use on H4? */ | ||
63 | if (machine_is_omap_h4()) | ||
64 | return; | ||
65 | |||
66 | omap_cfg_reg(J15_24XX_I2C2_SCL); | ||
67 | omap_cfg_reg(H19_24XX_I2C2_SDA); | ||
68 | (void) platform_device_register(&omap_i2c_device2); | ||
69 | } | ||
70 | |||
71 | #else | ||
72 | |||
73 | static void omap_init_i2c(void) {} | ||
74 | |||
75 | #endif | ||
76 | |||
77 | /*-------------------------------------------------------------------------*/ | ||
78 | |||
79 | static int __init omap2_init_devices(void) | ||
80 | { | ||
81 | /* please keep these calls, and their implementations above, | ||
82 | * in alphabetical order so they're easier to sort through. | ||
83 | */ | ||
84 | omap_init_i2c(); | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | arch_initcall(omap2_init_devices); | ||
89 | |||
diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c new file mode 100644 index 000000000000..76187300f2b6 --- /dev/null +++ b/arch/arm/mach-omap2/id.c | |||
@@ -0,0 +1,124 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-omap2/id.c | ||
3 | * | ||
4 | * OMAP2 CPU identification code | ||
5 | * | ||
6 | * Copyright (C) 2005 Nokia Corporation | ||
7 | * Written by Tony Lindgren <tony@atomide.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/init.h> | ||
18 | |||
19 | #include <asm/io.h> | ||
20 | |||
21 | #define OMAP24XX_TAP_BASE io_p2v(0x48014000) | ||
22 | |||
23 | #define OMAP_TAP_IDCODE 0x0204 | ||
24 | #define OMAP_TAP_PROD_ID 0x0208 | ||
25 | |||
26 | #define OMAP_TAP_DIE_ID_0 0x0218 | ||
27 | #define OMAP_TAP_DIE_ID_1 0x021C | ||
28 | #define OMAP_TAP_DIE_ID_2 0x0220 | ||
29 | #define OMAP_TAP_DIE_ID_3 0x0224 | ||
30 | |||
31 | /* system_rev fields for OMAP2 processors: | ||
32 | * CPU id bits [31:16], | ||
33 | * CPU device type [15:12], (unprg,normal,POP) | ||
34 | * CPU revision [11:08] | ||
35 | * CPU class bits [07:00] | ||
36 | */ | ||
37 | |||
38 | struct omap_id { | ||
39 | u16 hawkeye; /* Silicon type (Hawkeye id) */ | ||
40 | u8 dev; /* Device type from production_id reg */ | ||
41 | u32 type; /* combined type id copied to system_rev */ | ||
42 | }; | ||
43 | |||
44 | /* Register values to detect the OMAP version */ | ||
45 | static struct omap_id omap_ids[] __initdata = { | ||
46 | { .hawkeye = 0xb5d9, .dev = 0x0, .type = 0x24200000 }, | ||
47 | { .hawkeye = 0xb5d9, .dev = 0x1, .type = 0x24201000 }, | ||
48 | { .hawkeye = 0xb5d9, .dev = 0x2, .type = 0x24202000 }, | ||
49 | { .hawkeye = 0xb5d9, .dev = 0x4, .type = 0x24220000 }, | ||
50 | { .hawkeye = 0xb5d9, .dev = 0x8, .type = 0x24230000 }, | ||
51 | { .hawkeye = 0xb68a, .dev = 0x0, .type = 0x24300000 }, | ||
52 | }; | ||
53 | |||
54 | static u32 __init read_tap_reg(int reg) | ||
55 | { | ||
56 | return __raw_readl(OMAP24XX_TAP_BASE + reg); | ||
57 | } | ||
58 | |||
59 | void __init omap2_check_revision(void) | ||
60 | { | ||
61 | int i, j; | ||
62 | u32 idcode; | ||
63 | u32 prod_id; | ||
64 | u16 hawkeye; | ||
65 | u8 dev_type; | ||
66 | u8 rev; | ||
67 | |||
68 | idcode = read_tap_reg(OMAP_TAP_IDCODE); | ||
69 | prod_id = read_tap_reg(OMAP_TAP_PROD_ID); | ||
70 | hawkeye = (idcode >> 12) & 0xffff; | ||
71 | rev = (idcode >> 28) & 0x0f; | ||
72 | dev_type = (prod_id >> 16) & 0x0f; | ||
73 | |||
74 | #ifdef DEBUG | ||
75 | printk(KERN_DEBUG "OMAP_TAP_IDCODE 0x%08x REV %i HAWKEYE 0x%04x MANF %03x\n", | ||
76 | idcode, rev, hawkeye, (idcode >> 1) & 0x7ff); | ||
77 | printk(KERN_DEBUG "OMAP_TAP_DIE_ID_0: 0x%08x\n", | ||
78 | read_tap_reg(OMAP_TAP_DIE_ID_0)); | ||
79 | printk(KERN_DEBUG "OMAP_TAP_DIE_ID_1: 0x%08x DEV_REV: %i\n", | ||
80 | read_tap_reg(OMAP_TAP_DIE_ID_1), | ||
81 | (read_tap_reg(OMAP_TAP_DIE_ID_1) >> 28) & 0xf); | ||
82 | printk(KERN_DEBUG "OMAP_TAP_DIE_ID_2: 0x%08x\n", | ||
83 | read_tap_reg(OMAP_TAP_DIE_ID_2)); | ||
84 | printk(KERN_DEBUG "OMAP_TAP_DIE_ID_3: 0x%08x\n", | ||
85 | read_tap_reg(OMAP_TAP_DIE_ID_3)); | ||
86 | printk(KERN_DEBUG "OMAP_TAP_PROD_ID_0: 0x%08x DEV_TYPE: %i\n", | ||
87 | prod_id, dev_type); | ||
88 | #endif | ||
89 | |||
90 | /* Check hawkeye ids */ | ||
91 | for (i = 0; i < ARRAY_SIZE(omap_ids); i++) { | ||
92 | if (hawkeye == omap_ids[i].hawkeye) | ||
93 | break; | ||
94 | } | ||
95 | |||
96 | if (i == ARRAY_SIZE(omap_ids)) { | ||
97 | printk(KERN_ERR "Unknown OMAP CPU id\n"); | ||
98 | return; | ||
99 | } | ||
100 | |||
101 | for (j = i; j < ARRAY_SIZE(omap_ids); j++) { | ||
102 | if (dev_type == omap_ids[j].dev) | ||
103 | break; | ||
104 | } | ||
105 | |||
106 | if (j == ARRAY_SIZE(omap_ids)) { | ||
107 | printk(KERN_ERR "Unknown OMAP device type. " | ||
108 | "Handling it as OMAP%04x\n", | ||
109 | omap_ids[i].type >> 16); | ||
110 | j = i; | ||
111 | } | ||
112 | system_rev = omap_ids[j].type; | ||
113 | |||
114 | system_rev |= rev << 8; | ||
115 | |||
116 | /* Add the cpu class info (24xx) */ | ||
117 | system_rev |= 0x24; | ||
118 | |||
119 | pr_info("OMAP%04x", system_rev >> 16); | ||
120 | if ((system_rev >> 8) & 0x0f) | ||
121 | printk("%x", (system_rev >> 8) & 0x0f); | ||
122 | printk("\n"); | ||
123 | } | ||
124 | |||
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c new file mode 100644 index 000000000000..8ea67bf196a5 --- /dev/null +++ b/arch/arm/mach-omap2/io.c | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-omap2/io.c | ||
3 | * | ||
4 | * OMAP2 I/O mapping code | ||
5 | * | ||
6 | * Copyright (C) 2005 Nokia Corporation | ||
7 | * Author: Juha Yrjölä <juha.yrjola@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/init.h> | ||
18 | |||
19 | #include <asm/mach/map.h> | ||
20 | #include <asm/io.h> | ||
21 | #include <asm/arch/mux.h> | ||
22 | |||
23 | extern void omap_sram_init(void); | ||
24 | extern int omap2_clk_init(void); | ||
25 | extern void omap2_check_revision(void); | ||
26 | |||
27 | /* | ||
28 | * The machine specific code may provide the extra mapping besides the | ||
29 | * default mapping provided here. | ||
30 | */ | ||
31 | static struct map_desc omap2_io_desc[] __initdata = { | ||
32 | { | ||
33 | .virtual = L3_24XX_VIRT, | ||
34 | .pfn = __phys_to_pfn(L3_24XX_PHYS), | ||
35 | .length = L3_24XX_SIZE, | ||
36 | .type = MT_DEVICE | ||
37 | }, | ||
38 | { | ||
39 | .virtual = L4_24XX_VIRT, | ||
40 | .pfn = __phys_to_pfn(L4_24XX_PHYS), | ||
41 | .length = L4_24XX_SIZE, | ||
42 | .type = MT_DEVICE | ||
43 | } | ||
44 | }; | ||
45 | |||
46 | void __init omap_map_common_io(void) | ||
47 | { | ||
48 | iotable_init(omap2_io_desc, ARRAY_SIZE(omap2_io_desc)); | ||
49 | omap2_check_revision(); | ||
50 | omap_sram_init(); | ||
51 | omap2_mux_init(); | ||
52 | omap2_clk_init(); | ||
53 | } | ||
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c new file mode 100644 index 000000000000..d7baff675cfe --- /dev/null +++ b/arch/arm/mach-omap2/irq.c | |||
@@ -0,0 +1,149 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-omap/omap2/irq.c | ||
3 | * | ||
4 | * Interrupt handler for OMAP2 boards. | ||
5 | * | ||
6 | * Copyright (C) 2005 Nokia Corporation | ||
7 | * Author: Paul Mundt <paul.mundt@nokia.com> | ||
8 | * | ||
9 | * This file is subject to the terms and conditions of the GNU General Public | ||
10 | * License. See the file "COPYING" in the main directory of this archive | ||
11 | * for more details. | ||
12 | */ | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/config.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <asm/hardware.h> | ||
18 | #include <asm/mach/irq.h> | ||
19 | #include <asm/irq.h> | ||
20 | #include <asm/io.h> | ||
21 | |||
22 | #define INTC_REVISION 0x0000 | ||
23 | #define INTC_SYSCONFIG 0x0010 | ||
24 | #define INTC_SYSSTATUS 0x0014 | ||
25 | #define INTC_CONTROL 0x0048 | ||
26 | #define INTC_MIR_CLEAR0 0x0088 | ||
27 | #define INTC_MIR_SET0 0x008c | ||
28 | |||
29 | /* | ||
30 | * OMAP2 has a number of different interrupt controllers, each interrupt | ||
31 | * controller is identified as its own "bank". Register definitions are | ||
32 | * fairly consistent for each bank, but not all registers are implemented | ||
33 | * for each bank.. when in doubt, consult the TRM. | ||
34 | */ | ||
35 | static struct omap_irq_bank { | ||
36 | unsigned long base_reg; | ||
37 | unsigned int nr_irqs; | ||
38 | } __attribute__ ((aligned(4))) irq_banks[] = { | ||
39 | { | ||
40 | /* MPU INTC */ | ||
41 | .base_reg = OMAP24XX_IC_BASE, | ||
42 | .nr_irqs = 96, | ||
43 | }, { | ||
44 | /* XXX: DSP INTC */ | ||
45 | |||
46 | #if 0 | ||
47 | /* | ||
48 | * Commented out for now until we fix the IVA clocking | ||
49 | */ | ||
50 | #ifdef CONFIG_ARCH_OMAP2420 | ||
51 | }, { | ||
52 | /* IVA INTC (2420 only) */ | ||
53 | .base_reg = OMAP24XX_IVA_INTC_BASE, | ||
54 | .nr_irqs = 16, /* Actually 32, but only 16 are used */ | ||
55 | #endif | ||
56 | #endif | ||
57 | } | ||
58 | }; | ||
59 | |||
60 | /* XXX: FIQ and additional INTC support (only MPU at the moment) */ | ||
61 | static void omap_ack_irq(unsigned int irq) | ||
62 | { | ||
63 | omap_writel(0x1, irq_banks[0].base_reg + INTC_CONTROL); | ||
64 | } | ||
65 | |||
66 | static void omap_mask_irq(unsigned int irq) | ||
67 | { | ||
68 | int offset = (irq >> 5) << 5; | ||
69 | |||
70 | if (irq >= 64) { | ||
71 | irq %= 64; | ||
72 | } else if (irq >= 32) { | ||
73 | irq %= 32; | ||
74 | } | ||
75 | |||
76 | omap_writel(1 << irq, irq_banks[0].base_reg + INTC_MIR_SET0 + offset); | ||
77 | } | ||
78 | |||
79 | static void omap_unmask_irq(unsigned int irq) | ||
80 | { | ||
81 | int offset = (irq >> 5) << 5; | ||
82 | |||
83 | if (irq >= 64) { | ||
84 | irq %= 64; | ||
85 | } else if (irq >= 32) { | ||
86 | irq %= 32; | ||
87 | } | ||
88 | |||
89 | omap_writel(1 << irq, irq_banks[0].base_reg + INTC_MIR_CLEAR0 + offset); | ||
90 | } | ||
91 | |||
92 | static void omap_mask_ack_irq(unsigned int irq) | ||
93 | { | ||
94 | omap_mask_irq(irq); | ||
95 | omap_ack_irq(irq); | ||
96 | } | ||
97 | |||
98 | static struct irqchip omap_irq_chip = { | ||
99 | .ack = omap_mask_ack_irq, | ||
100 | .mask = omap_mask_irq, | ||
101 | .unmask = omap_unmask_irq, | ||
102 | }; | ||
103 | |||
104 | static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank) | ||
105 | { | ||
106 | unsigned long tmp; | ||
107 | |||
108 | tmp = omap_readl(bank->base_reg + INTC_REVISION) & 0xff; | ||
109 | printk(KERN_INFO "IRQ: Found an INTC at 0x%08lx " | ||
110 | "(revision %ld.%ld) with %d interrupts\n", | ||
111 | bank->base_reg, tmp >> 4, tmp & 0xf, bank->nr_irqs); | ||
112 | |||
113 | tmp = omap_readl(bank->base_reg + INTC_SYSCONFIG); | ||
114 | tmp |= 1 << 1; /* soft reset */ | ||
115 | omap_writel(tmp, bank->base_reg + INTC_SYSCONFIG); | ||
116 | |||
117 | while (!(omap_readl(bank->base_reg + INTC_SYSSTATUS) & 0x1)) | ||
118 | /* Wait for reset to complete */; | ||
119 | } | ||
120 | |||
121 | void __init omap_init_irq(void) | ||
122 | { | ||
123 | unsigned long nr_irqs = 0; | ||
124 | unsigned int nr_banks = 0; | ||
125 | int i; | ||
126 | |||
127 | for (i = 0; i < ARRAY_SIZE(irq_banks); i++) { | ||
128 | struct omap_irq_bank *bank = irq_banks + i; | ||
129 | |||
130 | /* XXX */ | ||
131 | if (!bank->base_reg) | ||
132 | continue; | ||
133 | |||
134 | omap_irq_bank_init_one(bank); | ||
135 | |||
136 | nr_irqs += bank->nr_irqs; | ||
137 | nr_banks++; | ||
138 | } | ||
139 | |||
140 | printk(KERN_INFO "Total of %ld interrupts on %d active controller%s\n", | ||
141 | nr_irqs, nr_banks, nr_banks > 1 ? "s" : ""); | ||
142 | |||
143 | for (i = 0; i < nr_irqs; i++) { | ||
144 | set_irq_chip(i, &omap_irq_chip); | ||
145 | set_irq_handler(i, do_level_IRQ); | ||
146 | set_irq_flags(i, IRQF_VALID); | ||
147 | } | ||
148 | } | ||
149 | |||
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c new file mode 100644 index 000000000000..ea4654815dd1 --- /dev/null +++ b/arch/arm/mach-omap2/mux.c | |||
@@ -0,0 +1,65 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-omap2/mux.c | ||
3 | * | ||
4 | * OMAP1 pin multiplexing configurations | ||
5 | * | ||
6 | * Copyright (C) 2003 - 2005 Nokia Corporation | ||
7 | * | ||
8 | * Written by Tony Lindgren <tony.lindgren@nokia.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
24 | */ | ||
25 | #include <linux/config.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <asm/system.h> | ||
29 | #include <asm/io.h> | ||
30 | #include <linux/spinlock.h> | ||
31 | |||
32 | #include <asm/arch/mux.h> | ||
33 | |||
34 | #ifdef CONFIG_OMAP_MUX | ||
35 | |||
36 | /* NOTE: See mux.h for the enumeration */ | ||
37 | |||
38 | struct pin_config __initdata_or_module omap24xx_pins[] = { | ||
39 | /* | ||
40 | * description mux mux pull pull debug | ||
41 | * offset mode ena type | ||
42 | */ | ||
43 | |||
44 | /* 24xx I2C */ | ||
45 | MUX_CFG_24XX("M19_24XX_I2C1_SCL", 0x111, 0, 0, 0, 1) | ||
46 | MUX_CFG_24XX("L15_24XX_I2C1_SDA", 0x112, 0, 0, 0, 1) | ||
47 | MUX_CFG_24XX("J15_24XX_I2C2_SCL", 0x113, 0, 0, 0, 1) | ||
48 | MUX_CFG_24XX("H19_24XX_I2C2_SDA", 0x114, 0, 0, 0, 1) | ||
49 | |||
50 | /* Menelaus interrupt */ | ||
51 | MUX_CFG_24XX("W19_24XX_SYS_NIRQ", 0x12c, 0, 1, 1, 1) | ||
52 | |||
53 | /* 24xx GPIO */ | ||
54 | MUX_CFG_24XX("Y20_24XX_GPIO60", 0x12c, 3, 0, 0, 1) | ||
55 | MUX_CFG_24XX("M15_24XX_GPIO92", 0x10a, 3, 0, 0, 1) | ||
56 | |||
57 | }; | ||
58 | |||
59 | int __init omap2_mux_init(void) | ||
60 | { | ||
61 | omap_mux_register(omap24xx_pins, ARRAY_SIZE(omap24xx_pins)); | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | #endif | ||
diff --git a/arch/arm/mach-omap2/prcm.h b/arch/arm/mach-omap2/prcm.h new file mode 100644 index 000000000000..2eb89b936c83 --- /dev/null +++ b/arch/arm/mach-omap2/prcm.h | |||
@@ -0,0 +1,419 @@ | |||
1 | /* | ||
2 | * prcm.h - Access definations for use in OMAP24XX clock and power management | ||
3 | * | ||
4 | * Copyright (C) 2005 Texas Instruments, Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #ifndef __ASM_ARM_ARCH_DPM_PRCM_H | ||
22 | #define __ASM_ARM_ARCH_DPM_PRCM_H | ||
23 | |||
24 | /* SET_PERFORMANCE_LEVEL PARAMETERS */ | ||
25 | #define PRCM_HALF_SPEED 1 | ||
26 | #define PRCM_FULL_SPEED 2 | ||
27 | |||
28 | #ifndef __ASSEMBLER__ | ||
29 | |||
30 | #define PRCM_REG32(offset) __REG32(OMAP24XX_PRCM_BASE + (offset)) | ||
31 | |||
32 | #define PRCM_REVISION PRCM_REG32(0x000) | ||
33 | #define PRCM_SYSCONFIG PRCM_REG32(0x010) | ||
34 | #define PRCM_IRQSTATUS_MPU PRCM_REG32(0x018) | ||
35 | #define PRCM_IRQENABLE_MPU PRCM_REG32(0x01C) | ||
36 | #define PRCM_VOLTCTRL PRCM_REG32(0x050) | ||
37 | #define PRCM_VOLTST PRCM_REG32(0x054) | ||
38 | #define PRCM_CLKSRC_CTRL PRCM_REG32(0x060) | ||
39 | #define PRCM_CLKOUT_CTRL PRCM_REG32(0x070) | ||
40 | #define PRCM_CLKEMUL_CTRL PRCM_REG32(0x078) | ||
41 | #define PRCM_CLKCFG_CTRL PRCM_REG32(0x080) | ||
42 | #define PRCM_CLKCFG_STATUS PRCM_REG32(0x084) | ||
43 | #define PRCM_VOLTSETUP PRCM_REG32(0x090) | ||
44 | #define PRCM_CLKSSETUP PRCM_REG32(0x094) | ||
45 | #define PRCM_POLCTRL PRCM_REG32(0x098) | ||
46 | |||
47 | /* GENERAL PURPOSE */ | ||
48 | #define GENERAL_PURPOSE1 PRCM_REG32(0x0B0) | ||
49 | #define GENERAL_PURPOSE2 PRCM_REG32(0x0B4) | ||
50 | #define GENERAL_PURPOSE3 PRCM_REG32(0x0B8) | ||
51 | #define GENERAL_PURPOSE4 PRCM_REG32(0x0BC) | ||
52 | #define GENERAL_PURPOSE5 PRCM_REG32(0x0C0) | ||
53 | #define GENERAL_PURPOSE6 PRCM_REG32(0x0C4) | ||
54 | #define GENERAL_PURPOSE7 PRCM_REG32(0x0C8) | ||
55 | #define GENERAL_PURPOSE8 PRCM_REG32(0x0CC) | ||
56 | #define GENERAL_PURPOSE9 PRCM_REG32(0x0D0) | ||
57 | #define GENERAL_PURPOSE10 PRCM_REG32(0x0D4) | ||
58 | #define GENERAL_PURPOSE11 PRCM_REG32(0x0D8) | ||
59 | #define GENERAL_PURPOSE12 PRCM_REG32(0x0DC) | ||
60 | #define GENERAL_PURPOSE13 PRCM_REG32(0x0E0) | ||
61 | #define GENERAL_PURPOSE14 PRCM_REG32(0x0E4) | ||
62 | #define GENERAL_PURPOSE15 PRCM_REG32(0x0E8) | ||
63 | #define GENERAL_PURPOSE16 PRCM_REG32(0x0EC) | ||
64 | #define GENERAL_PURPOSE17 PRCM_REG32(0x0F0) | ||
65 | #define GENERAL_PURPOSE18 PRCM_REG32(0x0F4) | ||
66 | #define GENERAL_PURPOSE19 PRCM_REG32(0x0F8) | ||
67 | #define GENERAL_PURPOSE20 PRCM_REG32(0x0FC) | ||
68 | |||
69 | /* MPU */ | ||
70 | #define CM_CLKSEL_MPU PRCM_REG32(0x140) | ||
71 | #define CM_CLKSTCTRL_MPU PRCM_REG32(0x148) | ||
72 | #define RM_RSTST_MPU PRCM_REG32(0x158) | ||
73 | #define PM_WKDEP_MPU PRCM_REG32(0x1C8) | ||
74 | #define PM_EVGENCTRL_MPU PRCM_REG32(0x1D4) | ||
75 | #define PM_EVEGENONTIM_MPU PRCM_REG32(0x1D8) | ||
76 | #define PM_EVEGENOFFTIM_MPU PRCM_REG32(0x1DC) | ||
77 | #define PM_PWSTCTRL_MPU PRCM_REG32(0x1E0) | ||
78 | #define PM_PWSTST_MPU PRCM_REG32(0x1E4) | ||
79 | |||
80 | /* CORE */ | ||
81 | #define CM_FCLKEN1_CORE PRCM_REG32(0x200) | ||
82 | #define CM_FCLKEN2_CORE PRCM_REG32(0x204) | ||
83 | #define CM_FCLKEN3_CORE PRCM_REG32(0x208) | ||
84 | #define CM_ICLKEN1_CORE PRCM_REG32(0x210) | ||
85 | #define CM_ICLKEN2_CORE PRCM_REG32(0x214) | ||
86 | #define CM_ICLKEN3_CORE PRCM_REG32(0x218) | ||
87 | #define CM_ICLKEN4_CORE PRCM_REG32(0x21C) | ||
88 | #define CM_IDLEST1_CORE PRCM_REG32(0x220) | ||
89 | #define CM_IDLEST2_CORE PRCM_REG32(0x224) | ||
90 | #define CM_IDLEST3_CORE PRCM_REG32(0x228) | ||
91 | #define CM_IDLEST4_CORE PRCM_REG32(0x22C) | ||
92 | #define CM_AUTOIDLE1_CORE PRCM_REG32(0x230) | ||
93 | #define CM_AUTOIDLE2_CORE PRCM_REG32(0x234) | ||
94 | #define CM_AUTOIDLE3_CORE PRCM_REG32(0x238) | ||
95 | #define CM_AUTOIDLE4_CORE PRCM_REG32(0x23C) | ||
96 | #define CM_CLKSEL1_CORE PRCM_REG32(0x240) | ||
97 | #define CM_CLKSEL2_CORE PRCM_REG32(0x244) | ||
98 | #define CM_CLKSTCTRL_CORE PRCM_REG32(0x248) | ||
99 | #define PM_WKEN1_CORE PRCM_REG32(0x2A0) | ||
100 | #define PM_WKEN2_CORE PRCM_REG32(0x2A4) | ||
101 | #define PM_WKST1_CORE PRCM_REG32(0x2B0) | ||
102 | #define PM_WKST2_CORE PRCM_REG32(0x2B4) | ||
103 | #define PM_WKDEP_CORE PRCM_REG32(0x2C8) | ||
104 | #define PM_PWSTCTRL_CORE PRCM_REG32(0x2E0) | ||
105 | #define PM_PWSTST_CORE PRCM_REG32(0x2E4) | ||
106 | |||
107 | /* GFX */ | ||
108 | #define CM_FCLKEN_GFX PRCM_REG32(0x300) | ||
109 | #define CM_ICLKEN_GFX PRCM_REG32(0x310) | ||
110 | #define CM_IDLEST_GFX PRCM_REG32(0x320) | ||
111 | #define CM_CLKSEL_GFX PRCM_REG32(0x340) | ||
112 | #define CM_CLKSTCTRL_GFX PRCM_REG32(0x348) | ||
113 | #define RM_RSTCTRL_GFX PRCM_REG32(0x350) | ||
114 | #define RM_RSTST_GFX PRCM_REG32(0x358) | ||
115 | #define PM_WKDEP_GFX PRCM_REG32(0x3C8) | ||
116 | #define PM_PWSTCTRL_GFX PRCM_REG32(0x3E0) | ||
117 | #define PM_PWSTST_GFX PRCM_REG32(0x3E4) | ||
118 | |||
119 | /* WAKE-UP */ | ||
120 | #define CM_FCLKEN_WKUP PRCM_REG32(0x400) | ||
121 | #define CM_ICLKEN_WKUP PRCM_REG32(0x410) | ||
122 | #define CM_IDLEST_WKUP PRCM_REG32(0x420) | ||
123 | #define CM_AUTOIDLE_WKUP PRCM_REG32(0x430) | ||
124 | #define CM_CLKSEL_WKUP PRCM_REG32(0x440) | ||
125 | #define RM_RSTCTRL_WKUP PRCM_REG32(0x450) | ||
126 | #define RM_RSTTIME_WKUP PRCM_REG32(0x454) | ||
127 | #define RM_RSTST_WKUP PRCM_REG32(0x458) | ||
128 | #define PM_WKEN_WKUP PRCM_REG32(0x4A0) | ||
129 | #define PM_WKST_WKUP PRCM_REG32(0x4B0) | ||
130 | |||
131 | /* CLOCKS */ | ||
132 | #define CM_CLKEN_PLL PRCM_REG32(0x500) | ||
133 | #define CM_IDLEST_CKGEN PRCM_REG32(0x520) | ||
134 | #define CM_AUTOIDLE_PLL PRCM_REG32(0x530) | ||
135 | #define CM_CLKSEL1_PLL PRCM_REG32(0x540) | ||
136 | #define CM_CLKSEL2_PLL PRCM_REG32(0x544) | ||
137 | |||
138 | /* DSP */ | ||
139 | #define CM_FCLKEN_DSP PRCM_REG32(0x800) | ||
140 | #define CM_ICLKEN_DSP PRCM_REG32(0x810) | ||
141 | #define CM_IDLEST_DSP PRCM_REG32(0x820) | ||
142 | #define CM_AUTOIDLE_DSP PRCM_REG32(0x830) | ||
143 | #define CM_CLKSEL_DSP PRCM_REG32(0x840) | ||
144 | #define CM_CLKSTCTRL_DSP PRCM_REG32(0x848) | ||
145 | #define RM_RSTCTRL_DSP PRCM_REG32(0x850) | ||
146 | #define RM_RSTST_DSP PRCM_REG32(0x858) | ||
147 | #define PM_WKEN_DSP PRCM_REG32(0x8A0) | ||
148 | #define PM_WKDEP_DSP PRCM_REG32(0x8C8) | ||
149 | #define PM_PWSTCTRL_DSP PRCM_REG32(0x8E0) | ||
150 | #define PM_PWSTST_DSP PRCM_REG32(0x8E4) | ||
151 | #define PRCM_IRQSTATUS_DSP PRCM_REG32(0x8F0) | ||
152 | #define PRCM_IRQENABLE_DSP PRCM_REG32(0x8F4) | ||
153 | |||
154 | /* IVA */ | ||
155 | #define PRCM_IRQSTATUS_IVA PRCM_REG32(0x8F8) | ||
156 | #define PRCM_IRQENABLE_IVA PRCM_REG32(0x8FC) | ||
157 | |||
158 | /* Modem on 2430 */ | ||
159 | #define CM_FCLKEN_MDM PRCM_REG32(0xC00) | ||
160 | #define CM_ICLKEN_MDM PRCM_REG32(0xC10) | ||
161 | #define CM_IDLEST_MDM PRCM_REG32(0xC20) | ||
162 | #define CM_CLKSEL_MDM PRCM_REG32(0xC40) | ||
163 | |||
164 | /* FIXME: Move to header for 2430 */ | ||
165 | #define DISP_BASE (OMAP24XX_L4_IO_BASE+0x50000) | ||
166 | #define DISP_REG32(offset) __REG32(DISP_BASE + (offset)) | ||
167 | |||
168 | #define GPMC_BASE (OMAP24XX_GPMC_BASE) | ||
169 | #define GPMC_REG32(offset) __REG32(GPMC_BASE + (offset)) | ||
170 | |||
171 | #define GPT1_BASE (OMAP24XX_GPT1) | ||
172 | #define GPT1_REG32(offset) __REG32(GPT1_BASE + (offset)) | ||
173 | |||
174 | /* Misc sysconfig */ | ||
175 | #define DISPC_SYSCONFIG DISP_REG32(0x410) | ||
176 | #define SPI_BASE (OMAP24XX_L4_IO_BASE+0x98000) | ||
177 | #define MCSPI1_SYSCONFIG __REG32(SPI_BASE + 0x10) | ||
178 | #define MCSPI2_SYSCONFIG __REG32(SPI_BASE+0x2000 + 0x10) | ||
179 | |||
180 | //#define DSP_MMU_SYSCONFIG 0x5A000010 | ||
181 | #define CAMERA_MMU_SYSCONFIG __REG32(DISP_BASE+0x2C10) | ||
182 | //#define IVA_MMU_SYSCONFIG 0x5D000010 | ||
183 | //#define DSP_DMA_SYSCONFIG 0x00FCC02C | ||
184 | #define CAMERA_DMA_SYSCONFIG __REG32(DISP_BASE+0x282C) | ||
185 | #define SYSTEM_DMA_SYSCONFIG __REG32(DISP_BASE+0x602C) | ||
186 | #define GPMC_SYSCONFIG GPMC_REG32(0x010) | ||
187 | #define MAILBOXES_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x94010) | ||
188 | #define UART1_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6A054) | ||
189 | #define UART2_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6C054) | ||
190 | #define UART3_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6E054) | ||
191 | //#define IVA_SYSCONFIG 0x5C060010 | ||
192 | #define SDRC_SYSCONFIG __REG32(OMAP24XX_SDRC_BASE+0x10) | ||
193 | #define SMS_SYSCONFIG __REG32(OMAP24XX_SMS_BASE+0x10) | ||
194 | #define SSI_SYSCONFIG __REG32(DISP_BASE+0x8010) | ||
195 | //#define VLYNQ_SYSCONFIG 0x67FFFE10 | ||
196 | |||
197 | /* rkw - good cannidates for PM_ to start what nm was trying */ | ||
198 | #define OMAP24XX_GPT2 (OMAP24XX_L4_IO_BASE+0x2A000) | ||
199 | #define OMAP24XX_GPT3 (OMAP24XX_L4_IO_BASE+0x78000) | ||
200 | #define OMAP24XX_GPT4 (OMAP24XX_L4_IO_BASE+0x7A000) | ||
201 | #define OMAP24XX_GPT5 (OMAP24XX_L4_IO_BASE+0x7C000) | ||
202 | #define OMAP24XX_GPT6 (OMAP24XX_L4_IO_BASE+0x7E000) | ||
203 | #define OMAP24XX_GPT7 (OMAP24XX_L4_IO_BASE+0x80000) | ||
204 | #define OMAP24XX_GPT8 (OMAP24XX_L4_IO_BASE+0x82000) | ||
205 | #define OMAP24XX_GPT9 (OMAP24XX_L4_IO_BASE+0x84000) | ||
206 | #define OMAP24XX_GPT10 (OMAP24XX_L4_IO_BASE+0x86000) | ||
207 | #define OMAP24XX_GPT11 (OMAP24XX_L4_IO_BASE+0x88000) | ||
208 | #define OMAP24XX_GPT12 (OMAP24XX_L4_IO_BASE+0x8A000) | ||
209 | |||
210 | #define GPTIMER1_SYSCONFIG GPT1_REG32(0x010) | ||
211 | #define GPTIMER2_SYSCONFIG __REG32(OMAP24XX_GPT2 + 0x10) | ||
212 | #define GPTIMER3_SYSCONFIG __REG32(OMAP24XX_GPT3 + 0x10) | ||
213 | #define GPTIMER4_SYSCONFIG __REG32(OMAP24XX_GPT4 + 0x10) | ||
214 | #define GPTIMER5_SYSCONFIG __REG32(OMAP24XX_GPT5 + 0x10) | ||
215 | #define GPTIMER6_SYSCONFIG __REG32(OMAP24XX_GPT6 + 0x10) | ||
216 | #define GPTIMER7_SYSCONFIG __REG32(OMAP24XX_GPT7 + 0x10) | ||
217 | #define GPTIMER8_SYSCONFIG __REG32(OMAP24XX_GPT8 + 0x10) | ||
218 | #define GPTIMER9_SYSCONFIG __REG32(OMAP24XX_GPT9 + 0x10) | ||
219 | #define GPTIMER10_SYSCONFIG __REG32(OMAP24XX_GPT10 + 0x10) | ||
220 | #define GPTIMER11_SYSCONFIG __REG32(OMAP24XX_GPT11 + 0x10) | ||
221 | #define GPTIMER12_SYSCONFIG __REG32(OMAP24XX_GPT12 + 0x10) | ||
222 | |||
223 | #define GPIOX_BASE(X) (OMAP24XX_GPIO_BASE+(0x2000*((X)-1))) | ||
224 | |||
225 | #define GPIO1_SYSCONFIG __REG32((GPIOX_BASE(1)+0x10)) | ||
226 | #define GPIO2_SYSCONFIG __REG32((GPIOX_BASE(2)+0x10)) | ||
227 | #define GPIO3_SYSCONFIG __REG32((GPIOX_BASE(3)+0x10)) | ||
228 | #define GPIO4_SYSCONFIG __REG32((GPIOX_BASE(4)+0x10)) | ||
229 | |||
230 | /* GP TIMER 1 */ | ||
231 | #define GPTIMER1_TISTAT GPT1_REG32(0x014) | ||
232 | #define GPTIMER1_TISR GPT1_REG32(0x018) | ||
233 | #define GPTIMER1_TIER GPT1_REG32(0x01C) | ||
234 | #define GPTIMER1_TWER GPT1_REG32(0x020) | ||
235 | #define GPTIMER1_TCLR GPT1_REG32(0x024) | ||
236 | #define GPTIMER1_TCRR GPT1_REG32(0x028) | ||
237 | #define GPTIMER1_TLDR GPT1_REG32(0x02C) | ||
238 | #define GPTIMER1_TTGR GPT1_REG32(0x030) | ||
239 | #define GPTIMER1_TWPS GPT1_REG32(0x034) | ||
240 | #define GPTIMER1_TMAR GPT1_REG32(0x038) | ||
241 | #define GPTIMER1_TCAR1 GPT1_REG32(0x03C) | ||
242 | #define GPTIMER1_TSICR GPT1_REG32(0x040) | ||
243 | #define GPTIMER1_TCAR2 GPT1_REG32(0x044) | ||
244 | |||
245 | /* rkw -- base fix up please... */ | ||
246 | #define GPTIMER3_TISR __REG32(OMAP24XX_L4_IO_BASE+0x78018) | ||
247 | |||
248 | /* SDRC */ | ||
249 | #define SDRC_DLLA_CTRL __REG32(OMAP24XX_SDRC_BASE+0x060) | ||
250 | #define SDRC_DLLA_STATUS __REG32(OMAP24XX_SDRC_BASE+0x064) | ||
251 | #define SDRC_DLLB_CTRL __REG32(OMAP24XX_SDRC_BASE+0x068) | ||
252 | #define SDRC_DLLB_STATUS __REG32(OMAP24XX_SDRC_BASE+0x06C) | ||
253 | #define SDRC_POWER __REG32(OMAP24XX_SDRC_BASE+0x070) | ||
254 | #define SDRC_MR_0 __REG32(OMAP24XX_SDRC_BASE+0x084) | ||
255 | |||
256 | /* GPIO 1 */ | ||
257 | #define GPIO1_BASE GPIOX_BASE(1) | ||
258 | #define GPIO1_REG32(offset) __REG32(GPIO1_BASE + (offset)) | ||
259 | #define GPIO1_IRQENABLE1 GPIO1_REG32(0x01C) | ||
260 | #define GPIO1_IRQSTATUS1 GPIO1_REG32(0x018) | ||
261 | #define GPIO1_IRQENABLE2 GPIO1_REG32(0x02C) | ||
262 | #define GPIO1_IRQSTATUS2 GPIO1_REG32(0x028) | ||
263 | #define GPIO1_WAKEUPENABLE GPIO1_REG32(0x020) | ||
264 | #define GPIO1_RISINGDETECT GPIO1_REG32(0x048) | ||
265 | #define GPIO1_DATAIN GPIO1_REG32(0x038) | ||
266 | #define GPIO1_OE GPIO1_REG32(0x034) | ||
267 | #define GPIO1_DATAOUT GPIO1_REG32(0x03C) | ||
268 | |||
269 | /* GPIO2 */ | ||
270 | #define GPIO2_BASE GPIOX_BASE(2) | ||
271 | #define GPIO2_REG32(offset) __REG32(GPIO2_BASE + (offset)) | ||
272 | #define GPIO2_IRQENABLE1 GPIO2_REG32(0x01C) | ||
273 | #define GPIO2_IRQSTATUS1 GPIO2_REG32(0x018) | ||
274 | #define GPIO2_IRQENABLE2 GPIO2_REG32(0x02C) | ||
275 | #define GPIO2_IRQSTATUS2 GPIO2_REG32(0x028) | ||
276 | #define GPIO2_WAKEUPENABLE GPIO2_REG32(0x020) | ||
277 | #define GPIO2_RISINGDETECT GPIO2_REG32(0x048) | ||
278 | #define GPIO2_DATAIN GPIO2_REG32(0x038) | ||
279 | #define GPIO2_OE GPIO2_REG32(0x034) | ||
280 | #define GPIO2_DATAOUT GPIO2_REG32(0x03C) | ||
281 | |||
282 | /* GPIO 3 */ | ||
283 | #define GPIO3_BASE GPIOX_BASE(3) | ||
284 | #define GPIO3_REG32(offset) __REG32(GPIO3_BASE + (offset)) | ||
285 | #define GPIO3_IRQENABLE1 GPIO3_REG32(0x01C) | ||
286 | #define GPIO3_IRQSTATUS1 GPIO3_REG32(0x018) | ||
287 | #define GPIO3_IRQENABLE2 GPIO3_REG32(0x02C) | ||
288 | #define GPIO3_IRQSTATUS2 GPIO3_REG32(0x028) | ||
289 | #define GPIO3_WAKEUPENABLE GPIO3_REG32(0x020) | ||
290 | #define GPIO3_RISINGDETECT GPIO3_REG32(0x048) | ||
291 | #define GPIO3_FALLINGDETECT GPIO3_REG32(0x04C) | ||
292 | #define GPIO3_DATAIN GPIO3_REG32(0x038) | ||
293 | #define GPIO3_OE GPIO3_REG32(0x034) | ||
294 | #define GPIO3_DATAOUT GPIO3_REG32(0x03C) | ||
295 | #define GPIO3_DEBOUNCENABLE GPIO3_REG32(0x050) | ||
296 | #define GPIO3_DEBOUNCINGTIME GPIO3_REG32(0x054) | ||
297 | |||
298 | /* GPIO 4 */ | ||
299 | #define GPIO4_BASE GPIOX_BASE(4) | ||
300 | #define GPIO4_REG32(offset) __REG32(GPIO4_BASE + (offset)) | ||
301 | #define GPIO4_IRQENABLE1 GPIO4_REG32(0x01C) | ||
302 | #define GPIO4_IRQSTATUS1 GPIO4_REG32(0x018) | ||
303 | #define GPIO4_IRQENABLE2 GPIO4_REG32(0x02C) | ||
304 | #define GPIO4_IRQSTATUS2 GPIO4_REG32(0x028) | ||
305 | #define GPIO4_WAKEUPENABLE GPIO4_REG32(0x020) | ||
306 | #define GPIO4_RISINGDETECT GPIO4_REG32(0x048) | ||
307 | #define GPIO4_FALLINGDETECT GPIO4_REG32(0x04C) | ||
308 | #define GPIO4_DATAIN GPIO4_REG32(0x038) | ||
309 | #define GPIO4_OE GPIO4_REG32(0x034) | ||
310 | #define GPIO4_DATAOUT GPIO4_REG32(0x03C) | ||
311 | #define GPIO4_DEBOUNCENABLE GPIO4_REG32(0x050) | ||
312 | #define GPIO4_DEBOUNCINGTIME GPIO4_REG32(0x054) | ||
313 | |||
314 | |||
315 | /* IO CONFIG */ | ||
316 | #define CONTROL_BASE (OMAP24XX_CTRL_BASE) | ||
317 | #define CONTROL_REG32(offset) __REG32(CONTROL_BASE + (offset)) | ||
318 | |||
319 | #define CONTROL_PADCONF_SPI1_NCS2 CONTROL_REG32(0x104) | ||
320 | #define CONTROL_PADCONF_SYS_XTALOUT CONTROL_REG32(0x134) | ||
321 | #define CONTROL_PADCONF_UART1_RX CONTROL_REG32(0x0C8) | ||
322 | #define CONTROL_PADCONF_MCBSP1_DX CONTROL_REG32(0x10C) | ||
323 | #define CONTROL_PADCONF_GPMC_NCS4 CONTROL_REG32(0x090) | ||
324 | #define CONTROL_PADCONF_DSS_D5 CONTROL_REG32(0x0B8) | ||
325 | #define CONTROL_PADCONF_DSS_D9 CONTROL_REG32(0x0BC) | ||
326 | #define CONTROL_PADCONF_DSS_D13 CONTROL_REG32(0x0C0) | ||
327 | #define CONTROL_PADCONF_DSS_VSYNC CONTROL_REG32(0x0CC) | ||
328 | |||
329 | /* CONTROL */ | ||
330 | #define CONTROL_DEVCONF CONTROL_REG32(0x274) | ||
331 | |||
332 | /* INTERRUPT CONTROLLER */ | ||
333 | #define INTC_BASE (OMAP24XX_L4_IO_BASE+0xfe000) | ||
334 | #define INTC_REG32(offset) __REG32(INTC_BASE + (offset)) | ||
335 | |||
336 | #define INTC1_U_BASE INTC_REG32(0x000) | ||
337 | #define INTC_MIR0 INTC_REG32(0x084) | ||
338 | #define INTC_MIR_SET0 INTC_REG32(0x08C) | ||
339 | #define INTC_MIR_CLEAR0 INTC_REG32(0x088) | ||
340 | #define INTC_ISR_CLEAR0 INTC_REG32(0x094) | ||
341 | #define INTC_MIR1 INTC_REG32(0x0A4) | ||
342 | #define INTC_MIR_SET1 INTC_REG32(0x0AC) | ||
343 | #define INTC_MIR_CLEAR1 INTC_REG32(0x0A8) | ||
344 | #define INTC_ISR_CLEAR1 INTC_REG32(0x0B4) | ||
345 | #define INTC_MIR2 INTC_REG32(0x0C4) | ||
346 | #define INTC_MIR_SET2 INTC_REG32(0x0CC) | ||
347 | #define INTC_MIR_CLEAR2 INTC_REG32(0x0C8) | ||
348 | #define INTC_ISR_CLEAR2 INTC_REG32(0x0D4) | ||
349 | #define INTC_SIR_IRQ INTC_REG32(0x040) | ||
350 | #define INTC_CONTROL INTC_REG32(0x048) | ||
351 | #define INTC_ILR11 INTC_REG32(0x12C) | ||
352 | #define INTC_ILR32 INTC_REG32(0x180) | ||
353 | #define INTC_ILR37 INTC_REG32(0x194) | ||
354 | #define INTC_SYSCONFIG INTC_REG32(0x010) | ||
355 | |||
356 | /* RAM FIREWALL */ | ||
357 | #define RAMFW_BASE (0x68005000) | ||
358 | #define RAMFW_REG32(offset) __REG32(RAMFW_BASE + (offset)) | ||
359 | |||
360 | #define RAMFW_REQINFOPERM0 RAMFW_REG32(0x048) | ||
361 | #define RAMFW_READPERM0 RAMFW_REG32(0x050) | ||
362 | #define RAMFW_WRITEPERM0 RAMFW_REG32(0x058) | ||
363 | |||
364 | /* GPMC CS1 FPGA ON USER INTERFACE MODULE */ | ||
365 | //#define DEBUG_BOARD_LED_REGISTER 0x04000014 | ||
366 | |||
367 | /* GPMC CS0 */ | ||
368 | #define GPMC_CONFIG1_0 GPMC_REG32(0x060) | ||
369 | #define GPMC_CONFIG2_0 GPMC_REG32(0x064) | ||
370 | #define GPMC_CONFIG3_0 GPMC_REG32(0x068) | ||
371 | #define GPMC_CONFIG4_0 GPMC_REG32(0x06C) | ||
372 | #define GPMC_CONFIG5_0 GPMC_REG32(0x070) | ||
373 | #define GPMC_CONFIG6_0 GPMC_REG32(0x074) | ||
374 | #define GPMC_CONFIG7_0 GPMC_REG32(0x078) | ||
375 | |||
376 | /* DSS */ | ||
377 | #define DSS_CONTROL DISP_REG32(0x040) | ||
378 | #define DISPC_CONTROL DISP_REG32(0x440) | ||
379 | #define DISPC_SYSSTATUS DISP_REG32(0x414) | ||
380 | #define DISPC_IRQSTATUS DISP_REG32(0x418) | ||
381 | #define DISPC_IRQENABLE DISP_REG32(0x41C) | ||
382 | #define DISPC_CONFIG DISP_REG32(0x444) | ||
383 | #define DISPC_DEFAULT_COLOR0 DISP_REG32(0x44C) | ||
384 | #define DISPC_DEFAULT_COLOR1 DISP_REG32(0x450) | ||
385 | #define DISPC_TRANS_COLOR0 DISP_REG32(0x454) | ||
386 | #define DISPC_TRANS_COLOR1 DISP_REG32(0x458) | ||
387 | #define DISPC_LINE_NUMBER DISP_REG32(0x460) | ||
388 | #define DISPC_TIMING_H DISP_REG32(0x464) | ||
389 | #define DISPC_TIMING_V DISP_REG32(0x468) | ||
390 | #define DISPC_POL_FREQ DISP_REG32(0x46C) | ||
391 | #define DISPC_DIVISOR DISP_REG32(0x470) | ||
392 | #define DISPC_SIZE_DIG DISP_REG32(0x478) | ||
393 | #define DISPC_SIZE_LCD DISP_REG32(0x47C) | ||
394 | #define DISPC_GFX_BA0 DISP_REG32(0x480) | ||
395 | #define DISPC_GFX_BA1 DISP_REG32(0x484) | ||
396 | #define DISPC_GFX_POSITION DISP_REG32(0x488) | ||
397 | #define DISPC_GFX_SIZE DISP_REG32(0x48C) | ||
398 | #define DISPC_GFX_ATTRIBUTES DISP_REG32(0x4A0) | ||
399 | #define DISPC_GFX_FIFO_THRESHOLD DISP_REG32(0x4A4) | ||
400 | #define DISPC_GFX_ROW_INC DISP_REG32(0x4AC) | ||
401 | #define DISPC_GFX_PIXEL_INC DISP_REG32(0x4B0) | ||
402 | #define DISPC_GFX_WINDOW_SKIP DISP_REG32(0x4B4) | ||
403 | #define DISPC_GFX_TABLE_BA DISP_REG32(0x4B8) | ||
404 | #define DISPC_DATA_CYCLE1 DISP_REG32(0x5D4) | ||
405 | #define DISPC_DATA_CYCLE2 DISP_REG32(0x5D8) | ||
406 | #define DISPC_DATA_CYCLE3 DISP_REG32(0x5DC) | ||
407 | |||
408 | /* Wake up define for board */ | ||
409 | #define GPIO97 (1 << 1) | ||
410 | #define GPIO88 (1 << 24) | ||
411 | |||
412 | #endif /* __ASSEMBLER__ */ | ||
413 | |||
414 | #endif | ||
415 | |||
416 | |||
417 | |||
418 | |||
419 | |||
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c new file mode 100644 index 000000000000..f4df04fe1dd8 --- /dev/null +++ b/arch/arm/mach-omap2/serial.c | |||
@@ -0,0 +1,180 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-omap/omap2/serial.c | ||
3 | * | ||
4 | * OMAP2 serial support. | ||
5 | * | ||
6 | * Copyright (C) 2005 Nokia Corporation | ||
7 | * Author: Paul Mundt <paul.mundt@nokia.com> | ||
8 | * | ||
9 | * Based off of arch/arm/mach-omap/omap1/serial.c | ||
10 | * | ||
11 | * This file is subject to the terms and conditions of the GNU General Public | ||
12 | * License. See the file "COPYING" in the main directory of this archive | ||
13 | * for more details. | ||
14 | */ | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/serial_8250.h> | ||
18 | #include <linux/serial_reg.h> | ||
19 | |||
20 | #include <asm/io.h> | ||
21 | #include <asm/hardware/clock.h> | ||
22 | |||
23 | #include <asm/arch/common.h> | ||
24 | #include <asm/arch/board.h> | ||
25 | |||
26 | static struct clk * uart1_ick = NULL; | ||
27 | static struct clk * uart1_fck = NULL; | ||
28 | static struct clk * uart2_ick = NULL; | ||
29 | static struct clk * uart2_fck = NULL; | ||
30 | static struct clk * uart3_ick = NULL; | ||
31 | static struct clk * uart3_fck = NULL; | ||
32 | |||
33 | static struct plat_serial8250_port serial_platform_data[] = { | ||
34 | { | ||
35 | .membase = (char *)IO_ADDRESS(OMAP_UART1_BASE), | ||
36 | .mapbase = (unsigned long)OMAP_UART1_BASE, | ||
37 | .irq = 72, | ||
38 | .flags = UPF_BOOT_AUTOCONF, | ||
39 | .iotype = UPIO_MEM, | ||
40 | .regshift = 2, | ||
41 | .uartclk = OMAP16XX_BASE_BAUD * 16, | ||
42 | }, { | ||
43 | .membase = (char *)IO_ADDRESS(OMAP_UART2_BASE), | ||
44 | .mapbase = (unsigned long)OMAP_UART2_BASE, | ||
45 | .irq = 73, | ||
46 | .flags = UPF_BOOT_AUTOCONF, | ||
47 | .iotype = UPIO_MEM, | ||
48 | .regshift = 2, | ||
49 | .uartclk = OMAP16XX_BASE_BAUD * 16, | ||
50 | }, { | ||
51 | .membase = (char *)IO_ADDRESS(OMAP_UART3_BASE), | ||
52 | .mapbase = (unsigned long)OMAP_UART3_BASE, | ||
53 | .irq = 74, | ||
54 | .flags = UPF_BOOT_AUTOCONF, | ||
55 | .iotype = UPIO_MEM, | ||
56 | .regshift = 2, | ||
57 | .uartclk = OMAP16XX_BASE_BAUD * 16, | ||
58 | }, { | ||
59 | .flags = 0 | ||
60 | } | ||
61 | }; | ||
62 | |||
63 | static inline unsigned int serial_read_reg(struct plat_serial8250_port *up, | ||
64 | int offset) | ||
65 | { | ||
66 | offset <<= up->regshift; | ||
67 | return (unsigned int)__raw_readb(up->membase + offset); | ||
68 | } | ||
69 | |||
70 | static inline void serial_write_reg(struct plat_serial8250_port *p, int offset, | ||
71 | int value) | ||
72 | { | ||
73 | offset <<= p->regshift; | ||
74 | __raw_writeb(value, (unsigned long)(p->membase + offset)); | ||
75 | } | ||
76 | |||
77 | /* | ||
78 | * Internal UARTs need to be initialized for the 8250 autoconfig to work | ||
79 | * properly. Note that the TX watermark initialization may not be needed | ||
80 | * once the 8250.c watermark handling code is merged. | ||
81 | */ | ||
82 | static inline void __init omap_serial_reset(struct plat_serial8250_port *p) | ||
83 | { | ||
84 | serial_write_reg(p, UART_OMAP_MDR1, 0x07); | ||
85 | serial_write_reg(p, UART_OMAP_SCR, 0x08); | ||
86 | serial_write_reg(p, UART_OMAP_MDR1, 0x00); | ||
87 | serial_write_reg(p, UART_OMAP_SYSC, 0x01); | ||
88 | } | ||
89 | |||
90 | void __init omap_serial_init() | ||
91 | { | ||
92 | int i; | ||
93 | const struct omap_uart_config *info; | ||
94 | |||
95 | /* | ||
96 | * Make sure the serial ports are muxed on at this point. | ||
97 | * You have to mux them off in device drivers later on | ||
98 | * if not needed. | ||
99 | */ | ||
100 | |||
101 | info = omap_get_config(OMAP_TAG_UART, | ||
102 | struct omap_uart_config); | ||
103 | |||
104 | if (info == NULL) | ||
105 | return; | ||
106 | |||
107 | for (i = 0; i < OMAP_MAX_NR_PORTS; i++) { | ||
108 | struct plat_serial8250_port *p = serial_platform_data + i; | ||
109 | |||
110 | if (!(info->enabled_uarts & (1 << i))) { | ||
111 | p->membase = 0; | ||
112 | p->mapbase = 0; | ||
113 | continue; | ||
114 | } | ||
115 | |||
116 | switch (i) { | ||
117 | case 0: | ||
118 | uart1_ick = clk_get(NULL, "uart1_ick"); | ||
119 | if (IS_ERR(uart1_ick)) | ||
120 | printk("Could not get uart1_ick\n"); | ||
121 | else { | ||
122 | clk_use(uart1_ick); | ||
123 | } | ||
124 | |||
125 | uart1_fck = clk_get(NULL, "uart1_fck"); | ||
126 | if (IS_ERR(uart1_fck)) | ||
127 | printk("Could not get uart1_fck\n"); | ||
128 | else { | ||
129 | clk_use(uart1_fck); | ||
130 | } | ||
131 | break; | ||
132 | case 1: | ||
133 | uart2_ick = clk_get(NULL, "uart2_ick"); | ||
134 | if (IS_ERR(uart2_ick)) | ||
135 | printk("Could not get uart2_ick\n"); | ||
136 | else { | ||
137 | clk_use(uart2_ick); | ||
138 | } | ||
139 | |||
140 | uart2_fck = clk_get(NULL, "uart2_fck"); | ||
141 | if (IS_ERR(uart2_fck)) | ||
142 | printk("Could not get uart2_fck\n"); | ||
143 | else { | ||
144 | clk_use(uart2_fck); | ||
145 | } | ||
146 | break; | ||
147 | case 2: | ||
148 | uart3_ick = clk_get(NULL, "uart3_ick"); | ||
149 | if (IS_ERR(uart3_ick)) | ||
150 | printk("Could not get uart3_ick\n"); | ||
151 | else { | ||
152 | clk_use(uart3_ick); | ||
153 | } | ||
154 | |||
155 | uart3_fck = clk_get(NULL, "uart3_fck"); | ||
156 | if (IS_ERR(uart3_fck)) | ||
157 | printk("Could not get uart3_fck\n"); | ||
158 | else { | ||
159 | clk_use(uart3_fck); | ||
160 | } | ||
161 | break; | ||
162 | } | ||
163 | |||
164 | omap_serial_reset(p); | ||
165 | } | ||
166 | } | ||
167 | |||
168 | static struct platform_device serial_device = { | ||
169 | .name = "serial8250", | ||
170 | .id = 0, | ||
171 | .dev = { | ||
172 | .platform_data = serial_platform_data, | ||
173 | }, | ||
174 | }; | ||
175 | |||
176 | static int __init omap_init(void) | ||
177 | { | ||
178 | return platform_device_register(&serial_device); | ||
179 | } | ||
180 | arch_initcall(omap_init); | ||
diff --git a/arch/arm/mach-omap2/sram-fn.S b/arch/arm/mach-omap2/sram-fn.S new file mode 100644 index 000000000000..2a869e203342 --- /dev/null +++ b/arch/arm/mach-omap2/sram-fn.S | |||
@@ -0,0 +1,333 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-omap1/sram.S | ||
3 | * | ||
4 | * Omap2 specific functions that need to be run in internal SRAM | ||
5 | * | ||
6 | * (C) Copyright 2004 | ||
7 | * Texas Instruments, <www.ti.com> | ||
8 | * Richard Woodruff <r-woodruff2@ti.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License as | ||
12 | * published by the Free Software Foundation; either version 2 of | ||
13 | * the License, or (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
23 | * MA 02111-1307 USA | ||
24 | */ | ||
25 | #include <linux/config.h> | ||
26 | #include <linux/linkage.h> | ||
27 | #include <asm/assembler.h> | ||
28 | #include <asm/arch/io.h> | ||
29 | #include <asm/hardware.h> | ||
30 | |||
31 | #include <asm/arch/prcm.h> | ||
32 | |||
33 | #define TIMER_32KSYNCT_CR_V IO_ADDRESS(OMAP24XX_32KSYNCT_BASE + 0x010) | ||
34 | |||
35 | #define CM_CLKSEL2_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE + 0x544) | ||
36 | #define PRCM_VOLTCTRL_V IO_ADDRESS(OMAP24XX_PRCM_BASE + 0x050) | ||
37 | #define PRCM_CLKCFG_CTRL_V IO_ADDRESS(OMAP24XX_PRCM_BASE + 0x080) | ||
38 | #define CM_CLKEN_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE + 0x500) | ||
39 | #define CM_IDLEST_CKGEN_V IO_ADDRESS(OMAP24XX_PRCM_BASE + 0x520) | ||
40 | #define CM_CLKSEL1_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE + 0x540) | ||
41 | |||
42 | #define SDRC_DLLA_CTRL_V IO_ADDRESS(OMAP24XX_SDRC_BASE + 0x060) | ||
43 | #define SDRC_RFR_CTRL_V IO_ADDRESS(OMAP24XX_SDRC_BASE + 0x0a4) | ||
44 | |||
45 | .text | ||
46 | |||
47 | ENTRY(sram_ddr_init) | ||
48 | stmfd sp!, {r0 - r12, lr} @ save registers on stack | ||
49 | |||
50 | mov r12, r2 @ capture CS1 vs CS0 | ||
51 | mov r8, r3 @ capture force parameter | ||
52 | |||
53 | /* frequency shift down */ | ||
54 | ldr r2, cm_clksel2_pll @ get address of dpllout reg | ||
55 | mov r3, #0x1 @ value for 1x operation | ||
56 | str r3, [r2] @ go to L1-freq operation | ||
57 | |||
58 | /* voltage shift down */ | ||
59 | mov r9, #0x1 @ set up for L1 voltage call | ||
60 | bl voltage_shift @ go drop voltage | ||
61 | |||
62 | /* dll lock mode */ | ||
63 | ldr r11, sdrc_dlla_ctrl @ addr of dlla ctrl | ||
64 | ldr r10, [r11] @ get current val | ||
65 | cmp r12, #0x1 @ cs1 base (2422 es2.05/1) | ||
66 | addeq r11, r11, #0x8 @ if cs1 base, move to DLLB | ||
67 | mvn r9, #0x4 @ mask to get clear bit2 | ||
68 | and r10, r10, r9 @ clear bit2 for lock mode. | ||
69 | orr r10, r10, #0x8 @ make sure DLL on (es2 bit pos) | ||
70 | orr r10, r10, #0x2 @ 90 degree phase for all below 133Mhz | ||
71 | str r10, [r11] @ commit to DLLA_CTRL | ||
72 | bl i_dll_wait @ wait for dll to lock | ||
73 | |||
74 | /* get dll value */ | ||
75 | add r11, r11, #0x4 @ get addr of status reg | ||
76 | ldr r10, [r11] @ get locked value | ||
77 | |||
78 | /* voltage shift up */ | ||
79 | mov r9, #0x0 @ shift back to L0-voltage | ||
80 | bl voltage_shift @ go raise voltage | ||
81 | |||
82 | /* frequency shift up */ | ||
83 | mov r3, #0x2 @ value for 2x operation | ||
84 | str r3, [r2] @ go to L0-freq operation | ||
85 | |||
86 | /* reset entry mode for dllctrl */ | ||
87 | sub r11, r11, #0x4 @ move from status to ctrl | ||
88 | cmp r12, #0x1 @ normalize if cs1 based | ||
89 | subeq r11, r11, #0x8 @ possibly back to DLLA | ||
90 | cmp r8, #0x1 @ if forced unlock exit | ||
91 | orreq r1, r1, #0x4 @ make sure exit with unlocked value | ||
92 | str r1, [r11] @ restore DLLA_CTRL high value | ||
93 | add r11, r11, #0x8 @ move to DLLB_CTRL addr | ||
94 | str r1, [r11] @ set value DLLB_CTRL | ||
95 | bl i_dll_wait @ wait for possible lock | ||
96 | |||
97 | /* set up for return, DDR should be good */ | ||
98 | str r10, [r0] @ write dll_status and return counter | ||
99 | ldmfd sp!, {r0 - r12, pc} @ restore regs and return | ||
100 | |||
101 | /* ensure the DLL has relocked */ | ||
102 | i_dll_wait: | ||
103 | mov r4, #0x800 @ delay DLL relock, min 0x400 L3 clocks | ||
104 | i_dll_delay: | ||
105 | subs r4, r4, #0x1 | ||
106 | bne i_dll_delay | ||
107 | mov pc, lr | ||
108 | |||
109 | /* | ||
110 | * shift up or down voltage, use R9 as input to tell level. | ||
111 | * wait for it to finish, use 32k sync counter, 1tick=31uS. | ||
112 | */ | ||
113 | voltage_shift: | ||
114 | ldr r4, prcm_voltctrl @ get addr of volt ctrl. | ||
115 | ldr r5, [r4] @ get value. | ||
116 | ldr r6, prcm_mask_val @ get value of mask | ||
117 | and r5, r5, r6 @ apply mask to clear bits | ||
118 | orr r5, r5, r9 @ bulld value for L0/L1-volt operation. | ||
119 | str r5, [r4] @ set up for change. | ||
120 | mov r3, #0x4000 @ get val for force | ||
121 | orr r5, r5, r3 @ build value for force | ||
122 | str r5, [r4] @ Force transition to L1 | ||
123 | |||
124 | ldr r3, timer_32ksynct_cr @ get addr of counter | ||
125 | ldr r5, [r3] @ get value | ||
126 | add r5, r5, #0x3 @ give it at most 93uS | ||
127 | volt_delay: | ||
128 | ldr r7, [r3] @ get timer value | ||
129 | cmp r5, r7 @ time up? | ||
130 | bhi volt_delay @ not yet->branch | ||
131 | mov pc, lr @ back to caller. | ||
132 | |||
133 | /* relative load constants */ | ||
134 | cm_clksel2_pll: | ||
135 | .word CM_CLKSEL2_PLL_V | ||
136 | sdrc_dlla_ctrl: | ||
137 | .word SDRC_DLLA_CTRL_V | ||
138 | prcm_voltctrl: | ||
139 | .word PRCM_VOLTCTRL_V | ||
140 | prcm_mask_val: | ||
141 | .word 0xFFFF3FFC | ||
142 | timer_32ksynct_cr: | ||
143 | .word TIMER_32KSYNCT_CR_V | ||
144 | ENTRY(sram_ddr_init_sz) | ||
145 | .word . - sram_ddr_init | ||
146 | |||
147 | /* | ||
148 | * Reprograms memory timings. | ||
149 | * r0 = [PRCM_FULL | PRCM_HALF] r1 = SDRC_DLLA_CTRL value r2 = [DDR | SDR] | ||
150 | * PRCM_FULL = 2, PRCM_HALF = 1, DDR = 1, SDR = 0 | ||
151 | */ | ||
152 | ENTRY(sram_reprogram_sdrc) | ||
153 | stmfd sp!, {r0 - r10, lr} @ save registers on stack | ||
154 | mov r3, #0x0 @ clear for mrc call | ||
155 | mcr p15, 0, r3, c7, c10, 4 @ memory barrier, finish ARM SDR/DDR | ||
156 | nop | ||
157 | nop | ||
158 | ldr r6, ddr_sdrc_rfr_ctrl @ get addr of refresh reg | ||
159 | ldr r5, [r6] @ get value | ||
160 | mov r5, r5, lsr #8 @ isolate rfr field and drop burst | ||
161 | |||
162 | cmp r0, #0x1 @ going to half speed? | ||
163 | movne r9, #0x0 @ if up set flag up for pre up, hi volt | ||
164 | |||
165 | blne voltage_shift_c @ adjust voltage | ||
166 | |||
167 | cmp r0, #0x1 @ going to half speed (post branch link) | ||
168 | moveq r5, r5, lsr #1 @ divide by 2 if to half | ||
169 | movne r5, r5, lsl #1 @ mult by 2 if to full | ||
170 | mov r5, r5, lsl #8 @ put rfr field back into place | ||
171 | add r5, r5, #0x1 @ turn on burst of 1 | ||
172 | ldr r4, ddr_cm_clksel2_pll @ get address of out reg | ||
173 | ldr r3, [r4] @ get curr value | ||
174 | orr r3, r3, #0x3 | ||
175 | bic r3, r3, #0x3 @ clear lower bits | ||
176 | orr r3, r3, r0 @ new state value | ||
177 | str r3, [r4] @ set new state (pll/x, x=1 or 2) | ||
178 | nop | ||
179 | nop | ||
180 | |||
181 | moveq r9, #0x1 @ if speed down, post down, drop volt | ||
182 | bleq voltage_shift_c | ||
183 | |||
184 | mcr p15, 0, r3, c7, c10, 4 @ memory barrier | ||
185 | str r5, [r6] @ set new RFR_1 value | ||
186 | add r6, r6, #0x30 @ get RFR_2 addr | ||
187 | str r5, [r6] @ set RFR_2 | ||
188 | nop | ||
189 | cmp r2, #0x1 @ (SDR or DDR) do we need to adjust DLL | ||
190 | bne freq_out @ leave if SDR, no DLL function | ||
191 | |||
192 | /* With DDR, we need to take care of the DLL for the frequency change */ | ||
193 | ldr r2, ddr_sdrc_dlla_ctrl @ addr of dlla ctrl | ||
194 | str r1, [r2] @ write out new SDRC_DLLA_CTRL | ||
195 | add r2, r2, #0x8 @ addr to SDRC_DLLB_CTRL | ||
196 | str r1, [r2] @ commit to SDRC_DLLB_CTRL | ||
197 | mov r1, #0x2000 @ wait DLL relock, min 0x400 L3 clocks | ||
198 | dll_wait: | ||
199 | subs r1, r1, #0x1 | ||
200 | bne dll_wait | ||
201 | freq_out: | ||
202 | ldmfd sp!, {r0 - r10, pc} @ restore regs and return | ||
203 | |||
204 | /* | ||
205 | * shift up or down voltage, use R9 as input to tell level. | ||
206 | * wait for it to finish, use 32k sync counter, 1tick=31uS. | ||
207 | */ | ||
208 | voltage_shift_c: | ||
209 | ldr r10, ddr_prcm_voltctrl @ get addr of volt ctrl | ||
210 | ldr r8, [r10] @ get value | ||
211 | ldr r7, ddr_prcm_mask_val @ get value of mask | ||
212 | and r8, r8, r7 @ apply mask to clear bits | ||
213 | orr r8, r8, r9 @ bulld value for L0/L1-volt operation. | ||
214 | str r8, [r10] @ set up for change. | ||
215 | mov r7, #0x4000 @ get val for force | ||
216 | orr r8, r8, r7 @ build value for force | ||
217 | str r8, [r10] @ Force transition to L1 | ||
218 | |||
219 | ldr r10, ddr_timer_32ksynct @ get addr of counter | ||
220 | ldr r8, [r10] @ get value | ||
221 | add r8, r8, #0x2 @ give it at most 62uS (min 31+) | ||
222 | volt_delay_c: | ||
223 | ldr r7, [r10] @ get timer value | ||
224 | cmp r8, r7 @ time up? | ||
225 | bhi volt_delay_c @ not yet->branch | ||
226 | mov pc, lr @ back to caller | ||
227 | |||
228 | ddr_cm_clksel2_pll: | ||
229 | .word CM_CLKSEL2_PLL_V | ||
230 | ddr_sdrc_dlla_ctrl: | ||
231 | .word SDRC_DLLA_CTRL_V | ||
232 | ddr_sdrc_rfr_ctrl: | ||
233 | .word SDRC_RFR_CTRL_V | ||
234 | ddr_prcm_voltctrl: | ||
235 | .word PRCM_VOLTCTRL_V | ||
236 | ddr_prcm_mask_val: | ||
237 | .word 0xFFFF3FFC | ||
238 | ddr_timer_32ksynct: | ||
239 | .word TIMER_32KSYNCT_CR_V | ||
240 | |||
241 | ENTRY(sram_reprogram_sdrc_sz) | ||
242 | .word . - sram_reprogram_sdrc | ||
243 | |||
244 | /* | ||
245 | * Set dividers and pll. Also recalculate DLL value for DDR and unlock mode. | ||
246 | */ | ||
247 | ENTRY(sram_set_prcm) | ||
248 | stmfd sp!, {r0-r12, lr} @ regs to stack | ||
249 | adr r4, pbegin @ addr of preload start | ||
250 | adr r8, pend @ addr of preload end | ||
251 | mcrr p15, 1, r8, r4, c12 @ preload into icache | ||
252 | pbegin: | ||
253 | /* move into fast relock bypass */ | ||
254 | ldr r8, pll_ctl @ get addr | ||
255 | ldr r5, [r8] @ get val | ||
256 | mvn r6, #0x3 @ clear mask | ||
257 | and r5, r5, r6 @ clear field | ||
258 | orr r7, r5, #0x2 @ fast relock val | ||
259 | str r7, [r8] @ go to fast relock | ||
260 | ldr r4, pll_stat @ addr of stat | ||
261 | block: | ||
262 | /* wait for bypass */ | ||
263 | ldr r8, [r4] @ stat value | ||
264 | and r8, r8, #0x3 @ mask for stat | ||
265 | cmp r8, #0x1 @ there yet | ||
266 | bne block @ loop if not | ||
267 | |||
268 | /* set new dpll dividers _after_ in bypass */ | ||
269 | ldr r4, pll_div @ get addr | ||
270 | str r0, [r4] @ set dpll ctrl val | ||
271 | |||
272 | ldr r4, set_config @ get addr | ||
273 | mov r8, #1 @ valid cfg msk | ||
274 | str r8, [r4] @ make dividers take | ||
275 | |||
276 | mov r4, #100 @ dead spin a bit | ||
277 | wait_a_bit: | ||
278 | subs r4, r4, #1 @ dec loop | ||
279 | bne wait_a_bit @ delay done? | ||
280 | |||
281 | /* check if staying in bypass */ | ||
282 | cmp r2, #0x1 @ stay in bypass? | ||
283 | beq pend @ jump over dpll relock | ||
284 | |||
285 | /* relock DPLL with new vals */ | ||
286 | ldr r5, pll_stat @ get addr | ||
287 | ldr r4, pll_ctl @ get addr | ||
288 | orr r8, r7, #0x3 @ val for lock dpll | ||
289 | str r8, [r4] @ set val | ||
290 | mov r0, #1000 @ dead spin a bit | ||
291 | wait_more: | ||
292 | subs r0, r0, #1 @ dec loop | ||
293 | bne wait_more @ delay done? | ||
294 | wait_lock: | ||
295 | ldr r8, [r5] @ get lock val | ||
296 | and r8, r8, #3 @ isolate field | ||
297 | cmp r8, #2 @ locked? | ||
298 | bne wait_lock @ wait if not | ||
299 | pend: | ||
300 | /* update memory timings & briefly lock dll */ | ||
301 | ldr r4, sdrc_rfr @ get addr | ||
302 | str r1, [r4] @ update refresh timing | ||
303 | ldr r11, dlla_ctrl @ get addr of DLLA ctrl | ||
304 | ldr r10, [r11] @ get current val | ||
305 | mvn r9, #0x4 @ mask to get clear bit2 | ||
306 | and r10, r10, r9 @ clear bit2 for lock mode | ||
307 | orr r10, r10, #0x8 @ make sure DLL on (es2 bit pos) | ||
308 | str r10, [r11] @ commit to DLLA_CTRL | ||
309 | add r11, r11, #0x8 @ move to dllb | ||
310 | str r10, [r11] @ hit DLLB also | ||
311 | |||
312 | mov r4, #0x800 @ relock time (min 0x400 L3 clocks) | ||
313 | wait_dll_lock: | ||
314 | subs r4, r4, #0x1 | ||
315 | bne wait_dll_lock | ||
316 | nop | ||
317 | ldmfd sp!, {r0-r12, pc} @ restore regs and return | ||
318 | |||
319 | set_config: | ||
320 | .word PRCM_CLKCFG_CTRL_V | ||
321 | pll_ctl: | ||
322 | .word CM_CLKEN_PLL_V | ||
323 | pll_stat: | ||
324 | .word CM_IDLEST_CKGEN_V | ||
325 | pll_div: | ||
326 | .word CM_CLKSEL1_PLL_V | ||
327 | sdrc_rfr: | ||
328 | .word SDRC_RFR_CTRL_V | ||
329 | dlla_ctrl: | ||
330 | .word SDRC_DLLA_CTRL_V | ||
331 | |||
332 | ENTRY(sram_set_prcm_sz) | ||
333 | .word . - sram_set_prcm | ||
diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c new file mode 100644 index 000000000000..9ec11443200f --- /dev/null +++ b/arch/arm/mach-omap2/timer-gp.c | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-omap2/timer-gp.c | ||
3 | * | ||
4 | * OMAP2 GP timer support. | ||
5 | * | ||
6 | * Copyright (C) 2005 Nokia Corporation | ||
7 | * Author: Paul Mundt <paul.mundt@nokia.com> | ||
8 | * Juha Yrjölä <juha.yrjola@nokia.com> | ||
9 | * | ||
10 | * Some parts based off of TI's 24xx code: | ||
11 | * | ||
12 | * Copyright (C) 2004 Texas Instruments, Inc. | ||
13 | * | ||
14 | * Roughly modelled after the OMAP1 MPU timer code. | ||
15 | * | ||
16 | * This file is subject to the terms and conditions of the GNU General Public | ||
17 | * License. See the file "COPYING" in the main directory of this archive | ||
18 | * for more details. | ||
19 | */ | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/time.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/err.h> | ||
24 | #include <asm/mach/time.h> | ||
25 | #include <asm/delay.h> | ||
26 | #include <asm/io.h> | ||
27 | #include <asm/hardware/clock.h> | ||
28 | |||
29 | #define OMAP2_GP_TIMER1_BASE 0x48028000 | ||
30 | #define OMAP2_GP_TIMER2_BASE 0x4802a000 | ||
31 | #define OMAP2_GP_TIMER3_BASE 0x48078000 | ||
32 | #define OMAP2_GP_TIMER4_BASE 0x4807a000 | ||
33 | |||
34 | #define GP_TIMER_TIDR 0x00 | ||
35 | #define GP_TIMER_TISR 0x18 | ||
36 | #define GP_TIMER_TIER 0x1c | ||
37 | #define GP_TIMER_TCLR 0x24 | ||
38 | #define GP_TIMER_TCRR 0x28 | ||
39 | #define GP_TIMER_TLDR 0x2c | ||
40 | #define GP_TIMER_TSICR 0x40 | ||
41 | |||
42 | #define OS_TIMER_NR 1 /* GP timer 2 */ | ||
43 | |||
44 | static unsigned long timer_base[] = { | ||
45 | IO_ADDRESS(OMAP2_GP_TIMER1_BASE), | ||
46 | IO_ADDRESS(OMAP2_GP_TIMER2_BASE), | ||
47 | IO_ADDRESS(OMAP2_GP_TIMER3_BASE), | ||
48 | IO_ADDRESS(OMAP2_GP_TIMER4_BASE), | ||
49 | }; | ||
50 | |||
51 | static inline unsigned int timer_read_reg(int nr, unsigned int reg) | ||
52 | { | ||
53 | return __raw_readl(timer_base[nr] + reg); | ||
54 | } | ||
55 | |||
56 | static inline void timer_write_reg(int nr, unsigned int reg, unsigned int val) | ||
57 | { | ||
58 | __raw_writel(val, timer_base[nr] + reg); | ||
59 | } | ||
60 | |||
61 | /* Note that we always enable the clock prescale divider bit */ | ||
62 | static inline void omap2_gp_timer_start(int nr, unsigned long load_val) | ||
63 | { | ||
64 | unsigned int tmp; | ||
65 | |||
66 | tmp = 0xffffffff - load_val; | ||
67 | |||
68 | timer_write_reg(nr, GP_TIMER_TLDR, tmp); | ||
69 | timer_write_reg(nr, GP_TIMER_TCRR, tmp); | ||
70 | timer_write_reg(nr, GP_TIMER_TIER, 1 << 1); | ||
71 | timer_write_reg(nr, GP_TIMER_TCLR, (1 << 5) | (1 << 1) | 1); | ||
72 | } | ||
73 | |||
74 | static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id, | ||
75 | struct pt_regs *regs) | ||
76 | { | ||
77 | write_seqlock(&xtime_lock); | ||
78 | |||
79 | timer_write_reg(OS_TIMER_NR, GP_TIMER_TISR, 1 << 1); | ||
80 | timer_tick(regs); | ||
81 | |||
82 | write_sequnlock(&xtime_lock); | ||
83 | |||
84 | return IRQ_HANDLED; | ||
85 | } | ||
86 | |||
87 | static struct irqaction omap2_gp_timer_irq = { | ||
88 | .name = "gp timer", | ||
89 | .flags = SA_INTERRUPT, | ||
90 | .handler = omap2_gp_timer_interrupt, | ||
91 | }; | ||
92 | |||
93 | static void __init omap2_gp_timer_init(void) | ||
94 | { | ||
95 | struct clk * sys_ck; | ||
96 | u32 tick_period = 120000; | ||
97 | u32 l; | ||
98 | |||
99 | /* Reset clock and prescale value */ | ||
100 | timer_write_reg(OS_TIMER_NR, GP_TIMER_TCLR, 0); | ||
101 | |||
102 | sys_ck = clk_get(NULL, "sys_ck"); | ||
103 | if (IS_ERR(sys_ck)) | ||
104 | printk(KERN_ERR "Could not get sys_ck\n"); | ||
105 | else { | ||
106 | clk_use(sys_ck); | ||
107 | tick_period = clk_get_rate(sys_ck) / 100; | ||
108 | clk_put(sys_ck); | ||
109 | } | ||
110 | |||
111 | tick_period /= 2; /* Minimum prescale divider is 2 */ | ||
112 | tick_period -= 1; | ||
113 | |||
114 | l = timer_read_reg(OS_TIMER_NR, GP_TIMER_TIDR); | ||
115 | printk(KERN_INFO "OMAP2 GP timer (HW version %d.%d)\n", | ||
116 | (l >> 4) & 0x0f, l & 0x0f); | ||
117 | |||
118 | setup_irq(38, &omap2_gp_timer_irq); | ||
119 | |||
120 | omap2_gp_timer_start(OS_TIMER_NR, tick_period); | ||
121 | } | ||
122 | |||
123 | struct sys_timer omap_timer = { | ||
124 | .init = omap2_gp_timer_init, | ||
125 | }; | ||
126 | |||
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index b380a438e68f..e201aa9765b9 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig | |||
@@ -60,6 +60,7 @@ config MACH_CORGI | |||
60 | bool "Enable Sharp SL-C700 (Corgi) Support" | 60 | bool "Enable Sharp SL-C700 (Corgi) Support" |
61 | depends PXA_SHARPSL_25x | 61 | depends PXA_SHARPSL_25x |
62 | select PXA_SHARP_C7xx | 62 | select PXA_SHARP_C7xx |
63 | select PXA_SSP | ||
63 | 64 | ||
64 | config MACH_SHEPHERD | 65 | config MACH_SHEPHERD |
65 | bool "Enable Sharp SL-C750 (Shepherd) Support" | 66 | bool "Enable Sharp SL-C750 (Shepherd) Support" |
@@ -102,12 +103,18 @@ config IWMMXT | |||
102 | 103 | ||
103 | config PXA_SHARP_C7xx | 104 | config PXA_SHARP_C7xx |
104 | bool | 105 | bool |
106 | select PXA_SSP | ||
105 | help | 107 | help |
106 | Enable support for all Sharp C7xx models | 108 | Enable support for all Sharp C7xx models |
107 | 109 | ||
108 | config PXA_SHARP_Cxx00 | 110 | config PXA_SHARP_Cxx00 |
109 | bool | 111 | bool |
112 | select PXA_SSP | ||
110 | help | 113 | help |
111 | Enable common support for Sharp Cxx00 models | 114 | Enable common support for Sharp Cxx00 models |
112 | 115 | ||
116 | config PXA_SSP | ||
117 | tristate | ||
118 | help | ||
119 | Enable support for PXA2xx SSP ports | ||
113 | endif | 120 | endif |
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index 8bc72d07cea8..d210bd5032ce 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile | |||
@@ -11,8 +11,8 @@ obj-$(CONFIG_PXA27x) += pxa27x.o | |||
11 | obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o | 11 | obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o |
12 | obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o | 12 | obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o |
13 | obj-$(CONFIG_ARCH_PXA_IDP) += idp.o | 13 | obj-$(CONFIG_ARCH_PXA_IDP) += idp.o |
14 | obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o corgi_ssp.o corgi_lcd.o ssp.o | 14 | obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o corgi_ssp.o corgi_lcd.o |
15 | obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o corgi_ssp.o corgi_lcd.o ssp.o | 15 | obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o corgi_ssp.o corgi_lcd.o |
16 | obj-$(CONFIG_MACH_POODLE) += poodle.o | 16 | obj-$(CONFIG_MACH_POODLE) += poodle.o |
17 | obj-$(CONFIG_MACH_TOSA) += tosa.o | 17 | obj-$(CONFIG_MACH_TOSA) += tosa.o |
18 | 18 | ||
@@ -26,6 +26,7 @@ obj-$(CONFIG_LEDS) += $(led-y) | |||
26 | 26 | ||
27 | # Misc features | 27 | # Misc features |
28 | obj-$(CONFIG_PM) += pm.o sleep.o | 28 | obj-$(CONFIG_PM) += pm.o sleep.o |
29 | obj-$(CONFIG_PXA_SSP) += ssp.o | ||
29 | 30 | ||
30 | ifeq ($(CONFIG_PXA27x),y) | 31 | ifeq ($(CONFIG_PXA27x),y) |
31 | obj-$(CONFIG_PM) += standby.o | 32 | obj-$(CONFIG_PM) += standby.o |
diff --git a/arch/arm/mach-pxa/corgi_ssp.c b/arch/arm/mach-pxa/corgi_ssp.c index 591e5f32dbec..bdf10cfa9440 100644 --- a/arch/arm/mach-pxa/corgi_ssp.c +++ b/arch/arm/mach-pxa/corgi_ssp.c | |||
@@ -203,7 +203,7 @@ static int __init corgi_ssp_probe(struct device *dev) | |||
203 | GPDR(ssp_machinfo->cs_ads7846) |= GPIO_bit(ssp_machinfo->cs_ads7846); /* output */ | 203 | GPDR(ssp_machinfo->cs_ads7846) |= GPIO_bit(ssp_machinfo->cs_ads7846); /* output */ |
204 | GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); /* High - Disable ADS7846*/ | 204 | GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); /* High - Disable ADS7846*/ |
205 | 205 | ||
206 | ret = ssp_init(&corgi_ssp_dev,ssp_machinfo->port); | 206 | ret = ssp_init(&corgi_ssp_dev, ssp_machinfo->port, 0); |
207 | 207 | ||
208 | if (ret) | 208 | if (ret) |
209 | printk(KERN_ERR "Unable to register SSP handler!\n"); | 209 | printk(KERN_ERR "Unable to register SSP handler!\n"); |
diff --git a/arch/arm/mach-pxa/sharpsl.h b/arch/arm/mach-pxa/sharpsl.h index 3977a77aacdd..4879c0f7da72 100644 --- a/arch/arm/mach-pxa/sharpsl.h +++ b/arch/arm/mach-pxa/sharpsl.h | |||
@@ -32,3 +32,90 @@ void corgi_put_hsync(void); | |||
32 | void spitz_put_hsync(void); | 32 | void spitz_put_hsync(void); |
33 | void corgi_wait_hsync(void); | 33 | void corgi_wait_hsync(void); |
34 | void spitz_wait_hsync(void); | 34 | void spitz_wait_hsync(void); |
35 | |||
36 | /* | ||
37 | * SharpSL Battery/PM Driver | ||
38 | */ | ||
39 | |||
40 | struct sharpsl_charger_machinfo { | ||
41 | void (*init)(void); | ||
42 | int gpio_acin; | ||
43 | int gpio_batfull; | ||
44 | int gpio_batlock; | ||
45 | int gpio_fatal; | ||
46 | int (*status_acin)(void); | ||
47 | void (*discharge)(int); | ||
48 | void (*discharge1)(int); | ||
49 | void (*charge)(int); | ||
50 | void (*chargeled)(int); | ||
51 | void (*measure_temp)(int); | ||
52 | void (*presuspend)(void); | ||
53 | void (*postsuspend)(void); | ||
54 | unsigned long (*charger_wakeup)(void); | ||
55 | int (*should_wakeup)(unsigned int resume_on_alarm); | ||
56 | int bat_levels; | ||
57 | struct battery_thresh *bat_levels_noac; | ||
58 | struct battery_thresh *bat_levels_acin; | ||
59 | int status_high_acin; | ||
60 | int status_low_acin; | ||
61 | int status_high_noac; | ||
62 | int status_low_noac; | ||
63 | }; | ||
64 | |||
65 | struct battery_thresh { | ||
66 | int voltage; | ||
67 | int percentage; | ||
68 | }; | ||
69 | |||
70 | struct battery_stat { | ||
71 | int ac_status; /* APM AC Present/Not Present */ | ||
72 | int mainbat_status; /* APM Main Battery Status */ | ||
73 | int mainbat_percent; /* Main Battery Percentage Charge */ | ||
74 | int mainbat_voltage; /* Main Battery Voltage */ | ||
75 | }; | ||
76 | |||
77 | struct sharpsl_pm_status { | ||
78 | struct device *dev; | ||
79 | struct timer_list ac_timer; | ||
80 | struct timer_list chrg_full_timer; | ||
81 | |||
82 | int charge_mode; | ||
83 | #define CHRG_ERROR (-1) | ||
84 | #define CHRG_OFF (0) | ||
85 | #define CHRG_ON (1) | ||
86 | #define CHRG_DONE (2) | ||
87 | |||
88 | unsigned int flags; | ||
89 | #define SHARPSL_SUSPENDED (1 << 0) /* Device is Suspended */ | ||
90 | #define SHARPSL_ALARM_ACTIVE (1 << 1) /* Alarm is for charging event (not user) */ | ||
91 | #define SHARPSL_BL_LIMIT (1 << 2) /* Backlight Intensity Limited */ | ||
92 | #define SHARPSL_APM_QUEUED (1 << 3) /* APM Event Queued */ | ||
93 | #define SHARPSL_DO_OFFLINE_CHRG (1 << 4) /* Trigger the offline charger */ | ||
94 | |||
95 | int full_count; | ||
96 | unsigned long charge_start_time; | ||
97 | struct sharpsl_charger_machinfo *machinfo; | ||
98 | struct battery_stat battstat; | ||
99 | }; | ||
100 | |||
101 | extern struct sharpsl_pm_status sharpsl_pm; | ||
102 | extern struct battery_thresh spitz_battery_levels_acin[]; | ||
103 | extern struct battery_thresh spitz_battery_levels_noac[]; | ||
104 | |||
105 | #define READ_GPIO_BIT(x) (GPLR(x) & GPIO_bit(x)) | ||
106 | |||
107 | #define SHARPSL_LED_ERROR 2 | ||
108 | #define SHARPSL_LED_ON 1 | ||
109 | #define SHARPSL_LED_OFF 0 | ||
110 | |||
111 | #define CHARGE_ON() sharpsl_pm.machinfo->charge(1) | ||
112 | #define CHARGE_OFF() sharpsl_pm.machinfo->charge(0) | ||
113 | #define CHARGE_LED_ON() sharpsl_pm.machinfo->chargeled(SHARPSL_LED_ON) | ||
114 | #define CHARGE_LED_OFF() sharpsl_pm.machinfo->chargeled(SHARPSL_LED_OFF) | ||
115 | #define CHARGE_LED_ERR() sharpsl_pm.machinfo->chargeled(SHARPSL_LED_ERROR) | ||
116 | #define DISCHARGE_ON() sharpsl_pm.machinfo->discharge(1) | ||
117 | #define DISCHARGE_OFF() sharpsl_pm.machinfo->discharge(0) | ||
118 | #define STATUS_AC_IN sharpsl_pm.machinfo->status_acin() | ||
119 | #define STATUS_BATT_LOCKED READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batlock) | ||
120 | #define STATUS_CHRG_FULL READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batfull) | ||
121 | #define STATUS_FATAL READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_fatal) | ||
diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c new file mode 100644 index 000000000000..6c9e871c53d8 --- /dev/null +++ b/arch/arm/mach-pxa/sharpsl_pm.c | |||
@@ -0,0 +1,992 @@ | |||
1 | /* | ||
2 | * Battery and Power Management code for the Sharp SL-C7xx and SL-Cxx00 | ||
3 | * series of PDAs | ||
4 | * | ||
5 | * Copyright (c) 2004-2005 Richard Purdie | ||
6 | * | ||
7 | * Based on code written by Sharp for 2.4 kernels | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #undef DEBUG | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/timer.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/apm_bios.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/device.h> | ||
25 | |||
26 | #include <asm/hardware.h> | ||
27 | #include <asm/hardware/scoop.h> | ||
28 | #include <asm/mach-types.h> | ||
29 | #include <asm/irq.h> | ||
30 | #include <asm/apm.h> | ||
31 | |||
32 | #include <asm/arch/pm.h> | ||
33 | #include <asm/arch/pxa-regs.h> | ||
34 | #include <asm/arch/sharpsl.h> | ||
35 | #include "sharpsl.h" | ||
36 | |||
37 | /* | ||
38 | * Constants | ||
39 | */ | ||
40 | #define SHARPSL_CHARGE_ON_TIME_INTERVAL (msecs_to_jiffies(1*60*1000)) /* 1 min */ | ||
41 | #define SHARPSL_CHARGE_FINISH_TIME (msecs_to_jiffies(10*60*1000)) /* 10 min */ | ||
42 | #define SHARPSL_BATCHK_TIME (msecs_to_jiffies(15*1000)) /* 15 sec */ | ||
43 | #define SHARPSL_BATCHK_TIME_SUSPEND (60*10) /* 10 min */ | ||
44 | #define SHARPSL_WAIT_CO_TIME 15 /* 15 sec */ | ||
45 | #define SHARPSL_WAIT_DISCHARGE_ON 100 /* 100 msec */ | ||
46 | #define SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP 10 /* 10 msec */ | ||
47 | #define SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT 10 /* 10 msec */ | ||
48 | #define SHARPSL_CHECK_BATTERY_WAIT_TIME_JKVAD 10 /* 10 msec */ | ||
49 | #define SHARPSL_CHARGE_WAIT_TIME 15 /* 15 msec */ | ||
50 | #define SHARPSL_CHARGE_CO_CHECK_TIME 5 /* 5 msec */ | ||
51 | #define SHARPSL_CHARGE_RETRY_CNT 1 /* eqv. 10 min */ | ||
52 | |||
53 | #define SHARPSL_CHARGE_ON_VOLT 0x99 /* 2.9V */ | ||
54 | #define SHARPSL_CHARGE_ON_TEMP 0xe0 /* 2.9V */ | ||
55 | #define SHARPSL_CHARGE_ON_JKVAD_HIGH 0x9b /* 6V */ | ||
56 | #define SHARPSL_CHARGE_ON_JKVAD_LOW 0x34 /* 2V */ | ||
57 | #define SHARPSL_FATAL_ACIN_VOLT 182 /* 3.45V */ | ||
58 | #define SHARPSL_FATAL_NOACIN_VOLT 170 /* 3.40V */ | ||
59 | |||
60 | struct battery_thresh spitz_battery_levels_acin[] = { | ||
61 | { 213, 100}, | ||
62 | { 212, 98}, | ||
63 | { 211, 95}, | ||
64 | { 210, 93}, | ||
65 | { 209, 90}, | ||
66 | { 208, 88}, | ||
67 | { 207, 85}, | ||
68 | { 206, 83}, | ||
69 | { 205, 80}, | ||
70 | { 204, 78}, | ||
71 | { 203, 75}, | ||
72 | { 202, 73}, | ||
73 | { 201, 70}, | ||
74 | { 200, 68}, | ||
75 | { 199, 65}, | ||
76 | { 198, 63}, | ||
77 | { 197, 60}, | ||
78 | { 196, 58}, | ||
79 | { 195, 55}, | ||
80 | { 194, 53}, | ||
81 | { 193, 50}, | ||
82 | { 192, 48}, | ||
83 | { 192, 45}, | ||
84 | { 191, 43}, | ||
85 | { 191, 40}, | ||
86 | { 190, 38}, | ||
87 | { 190, 35}, | ||
88 | { 189, 33}, | ||
89 | { 188, 30}, | ||
90 | { 187, 28}, | ||
91 | { 186, 25}, | ||
92 | { 185, 23}, | ||
93 | { 184, 20}, | ||
94 | { 183, 18}, | ||
95 | { 182, 15}, | ||
96 | { 181, 13}, | ||
97 | { 180, 10}, | ||
98 | { 179, 8}, | ||
99 | { 178, 5}, | ||
100 | { 0, 0}, | ||
101 | }; | ||
102 | |||
103 | struct battery_thresh spitz_battery_levels_noac[] = { | ||
104 | { 213, 100}, | ||
105 | { 212, 98}, | ||
106 | { 211, 95}, | ||
107 | { 210, 93}, | ||
108 | { 209, 90}, | ||
109 | { 208, 88}, | ||
110 | { 207, 85}, | ||
111 | { 206, 83}, | ||
112 | { 205, 80}, | ||
113 | { 204, 78}, | ||
114 | { 203, 75}, | ||
115 | { 202, 73}, | ||
116 | { 201, 70}, | ||
117 | { 200, 68}, | ||
118 | { 199, 65}, | ||
119 | { 198, 63}, | ||
120 | { 197, 60}, | ||
121 | { 196, 58}, | ||
122 | { 195, 55}, | ||
123 | { 194, 53}, | ||
124 | { 193, 50}, | ||
125 | { 192, 48}, | ||
126 | { 191, 45}, | ||
127 | { 190, 43}, | ||
128 | { 189, 40}, | ||
129 | { 188, 38}, | ||
130 | { 187, 35}, | ||
131 | { 186, 33}, | ||
132 | { 185, 30}, | ||
133 | { 184, 28}, | ||
134 | { 183, 25}, | ||
135 | { 182, 23}, | ||
136 | { 181, 20}, | ||
137 | { 180, 18}, | ||
138 | { 179, 15}, | ||
139 | { 178, 13}, | ||
140 | { 177, 10}, | ||
141 | { 176, 8}, | ||
142 | { 175, 5}, | ||
143 | { 0, 0}, | ||
144 | }; | ||
145 | |||
146 | /* MAX1111 Commands */ | ||
147 | #define MAXCTRL_PD0 1u << 0 | ||
148 | #define MAXCTRL_PD1 1u << 1 | ||
149 | #define MAXCTRL_SGL 1u << 2 | ||
150 | #define MAXCTRL_UNI 1u << 3 | ||
151 | #define MAXCTRL_SEL_SH 4 | ||
152 | #define MAXCTRL_STR 1u << 7 | ||
153 | |||
154 | /* MAX1111 Channel Definitions */ | ||
155 | #define BATT_AD 4u | ||
156 | #define BATT_THM 2u | ||
157 | #define JK_VAD 6u | ||
158 | |||
159 | |||
160 | /* | ||
161 | * Prototypes | ||
162 | */ | ||
163 | static int sharpsl_read_MainBattery(void); | ||
164 | static int sharpsl_off_charge_battery(void); | ||
165 | static int sharpsl_check_battery(int mode); | ||
166 | static int sharpsl_ac_check(void); | ||
167 | static int sharpsl_fatal_check(void); | ||
168 | static int sharpsl_average_value(int ad); | ||
169 | static void sharpsl_average_clear(void); | ||
170 | static void sharpsl_charge_toggle(void *private_); | ||
171 | static void sharpsl_battery_thread(void *private_); | ||
172 | |||
173 | |||
174 | /* | ||
175 | * Variables | ||
176 | */ | ||
177 | struct sharpsl_pm_status sharpsl_pm; | ||
178 | DECLARE_WORK(toggle_charger, sharpsl_charge_toggle, NULL); | ||
179 | DECLARE_WORK(sharpsl_bat, sharpsl_battery_thread, NULL); | ||
180 | |||
181 | |||
182 | static int get_percentage(int voltage) | ||
183 | { | ||
184 | int i = sharpsl_pm.machinfo->bat_levels - 1; | ||
185 | struct battery_thresh *thresh; | ||
186 | |||
187 | if (sharpsl_pm.charge_mode == CHRG_ON) | ||
188 | thresh=sharpsl_pm.machinfo->bat_levels_acin; | ||
189 | else | ||
190 | thresh=sharpsl_pm.machinfo->bat_levels_noac; | ||
191 | |||
192 | while (i > 0 && (voltage > thresh[i].voltage)) | ||
193 | i--; | ||
194 | |||
195 | return thresh[i].percentage; | ||
196 | } | ||
197 | |||
198 | static int get_apm_status(int voltage) | ||
199 | { | ||
200 | int low_thresh, high_thresh; | ||
201 | |||
202 | if (sharpsl_pm.charge_mode == CHRG_ON) { | ||
203 | high_thresh = sharpsl_pm.machinfo->status_high_acin; | ||
204 | low_thresh = sharpsl_pm.machinfo->status_low_acin; | ||
205 | } else { | ||
206 | high_thresh = sharpsl_pm.machinfo->status_high_noac; | ||
207 | low_thresh = sharpsl_pm.machinfo->status_low_noac; | ||
208 | } | ||
209 | |||
210 | if (voltage >= high_thresh) | ||
211 | return APM_BATTERY_STATUS_HIGH; | ||
212 | if (voltage >= low_thresh) | ||
213 | return APM_BATTERY_STATUS_LOW; | ||
214 | return APM_BATTERY_STATUS_CRITICAL; | ||
215 | } | ||
216 | |||
217 | void sharpsl_battery_kick(void) | ||
218 | { | ||
219 | schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(125)); | ||
220 | } | ||
221 | EXPORT_SYMBOL(sharpsl_battery_kick); | ||
222 | |||
223 | |||
224 | static void sharpsl_battery_thread(void *private_) | ||
225 | { | ||
226 | int voltage, percent, apm_status, i = 0; | ||
227 | |||
228 | if (!sharpsl_pm.machinfo) | ||
229 | return; | ||
230 | |||
231 | sharpsl_pm.battstat.ac_status = (!(STATUS_AC_IN) ? APM_AC_OFFLINE : APM_AC_ONLINE); | ||
232 | |||
233 | /* Corgi cannot confirm when battery fully charged so periodically kick! */ | ||
234 | if (machine_is_corgi() && (sharpsl_pm.charge_mode == CHRG_ON) | ||
235 | && time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_ON_TIME_INTERVAL)) | ||
236 | schedule_work(&toggle_charger); | ||
237 | |||
238 | while(1) { | ||
239 | voltage = sharpsl_read_MainBattery(); | ||
240 | if (voltage > 0) break; | ||
241 | if (i++ > 5) { | ||
242 | voltage = sharpsl_pm.machinfo->bat_levels_noac[0].voltage; | ||
243 | dev_warn(sharpsl_pm.dev, "Warning: Cannot read main battery!\n"); | ||
244 | break; | ||
245 | } | ||
246 | } | ||
247 | |||
248 | voltage = sharpsl_average_value(voltage); | ||
249 | apm_status = get_apm_status(voltage); | ||
250 | percent = get_percentage(voltage); | ||
251 | |||
252 | /* At low battery voltages, the voltage has a tendency to start | ||
253 | creeping back up so we try to avoid this here */ | ||
254 | if ((sharpsl_pm.battstat.ac_status == APM_AC_ONLINE) || (apm_status == APM_BATTERY_STATUS_HIGH) || percent <= sharpsl_pm.battstat.mainbat_percent) { | ||
255 | sharpsl_pm.battstat.mainbat_voltage = voltage; | ||
256 | sharpsl_pm.battstat.mainbat_status = apm_status; | ||
257 | sharpsl_pm.battstat.mainbat_percent = percent; | ||
258 | } | ||
259 | |||
260 | dev_dbg(sharpsl_pm.dev, "Battery: voltage: %d, status: %d, percentage: %d, time: %d\n", voltage, | ||
261 | sharpsl_pm.battstat.mainbat_status, sharpsl_pm.battstat.mainbat_percent, jiffies); | ||
262 | |||
263 | /* If battery is low. limit backlight intensity to save power. */ | ||
264 | if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE) | ||
265 | && ((sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_LOW) || | ||
266 | (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL))) { | ||
267 | if (!(sharpsl_pm.flags & SHARPSL_BL_LIMIT)) { | ||
268 | corgibl_limit_intensity(1); | ||
269 | sharpsl_pm.flags |= SHARPSL_BL_LIMIT; | ||
270 | } | ||
271 | } else if (sharpsl_pm.flags & SHARPSL_BL_LIMIT) { | ||
272 | corgibl_limit_intensity(0); | ||
273 | sharpsl_pm.flags &= ~SHARPSL_BL_LIMIT; | ||
274 | } | ||
275 | |||
276 | /* Suspend if critical battery level */ | ||
277 | if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE) | ||
278 | && (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL) | ||
279 | && !(sharpsl_pm.flags & SHARPSL_APM_QUEUED)) { | ||
280 | sharpsl_pm.flags |= SHARPSL_APM_QUEUED; | ||
281 | dev_err(sharpsl_pm.dev, "Fatal Off\n"); | ||
282 | apm_queue_event(APM_CRITICAL_SUSPEND); | ||
283 | } | ||
284 | |||
285 | schedule_delayed_work(&sharpsl_bat, SHARPSL_BATCHK_TIME); | ||
286 | } | ||
287 | |||
288 | static void sharpsl_charge_on(void) | ||
289 | { | ||
290 | dev_dbg(sharpsl_pm.dev, "Turning Charger On\n"); | ||
291 | |||
292 | sharpsl_pm.full_count = 0; | ||
293 | sharpsl_pm.charge_mode = CHRG_ON; | ||
294 | schedule_delayed_work(&toggle_charger, msecs_to_jiffies(250)); | ||
295 | schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(500)); | ||
296 | } | ||
297 | |||
298 | static void sharpsl_charge_off(void) | ||
299 | { | ||
300 | dev_dbg(sharpsl_pm.dev, "Turning Charger Off\n"); | ||
301 | |||
302 | CHARGE_OFF(); | ||
303 | CHARGE_LED_OFF(); | ||
304 | sharpsl_pm.charge_mode = CHRG_OFF; | ||
305 | |||
306 | schedule_work(&sharpsl_bat); | ||
307 | } | ||
308 | |||
309 | static void sharpsl_charge_error(void) | ||
310 | { | ||
311 | CHARGE_LED_ERR(); | ||
312 | CHARGE_OFF(); | ||
313 | sharpsl_pm.charge_mode = CHRG_ERROR; | ||
314 | } | ||
315 | |||
316 | static void sharpsl_charge_toggle(void *private_) | ||
317 | { | ||
318 | dev_dbg(sharpsl_pm.dev, "Toogling Charger at time: %lx\n", jiffies); | ||
319 | |||
320 | if (STATUS_AC_IN == 0) { | ||
321 | sharpsl_charge_off(); | ||
322 | return; | ||
323 | } else if ((sharpsl_check_battery(1) < 0) || (sharpsl_ac_check() < 0)) { | ||
324 | sharpsl_charge_error(); | ||
325 | return; | ||
326 | } | ||
327 | |||
328 | CHARGE_LED_ON(); | ||
329 | CHARGE_OFF(); | ||
330 | mdelay(SHARPSL_CHARGE_WAIT_TIME); | ||
331 | CHARGE_ON(); | ||
332 | |||
333 | sharpsl_pm.charge_start_time = jiffies; | ||
334 | } | ||
335 | |||
336 | static void sharpsl_ac_timer(unsigned long data) | ||
337 | { | ||
338 | int acin = STATUS_AC_IN; | ||
339 | |||
340 | dev_dbg(sharpsl_pm.dev, "AC Status: %d\n",acin); | ||
341 | |||
342 | sharpsl_average_clear(); | ||
343 | if (acin && (sharpsl_pm.charge_mode != CHRG_ON)) | ||
344 | sharpsl_charge_on(); | ||
345 | else if (sharpsl_pm.charge_mode == CHRG_ON) | ||
346 | sharpsl_charge_off(); | ||
347 | |||
348 | schedule_work(&sharpsl_bat); | ||
349 | } | ||
350 | |||
351 | |||
352 | static irqreturn_t sharpsl_ac_isr(int irq, void *dev_id, struct pt_regs *fp) | ||
353 | { | ||
354 | /* Delay the event slightly to debounce */ | ||
355 | /* Must be a smaller delay than the chrg_full_isr below */ | ||
356 | mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250)); | ||
357 | |||
358 | return IRQ_HANDLED; | ||
359 | } | ||
360 | |||
361 | static void sharpsl_chrg_full_timer(unsigned long data) | ||
362 | { | ||
363 | dev_dbg(sharpsl_pm.dev, "Charge Full at time: %lx\n", jiffies); | ||
364 | |||
365 | sharpsl_pm.full_count++; | ||
366 | |||
367 | if (STATUS_AC_IN == 0) { | ||
368 | dev_dbg(sharpsl_pm.dev, "Charge Full: AC removed - stop charging!\n"); | ||
369 | if (sharpsl_pm.charge_mode == CHRG_ON) | ||
370 | sharpsl_charge_off(); | ||
371 | } else if (sharpsl_pm.full_count < 2) { | ||
372 | dev_dbg(sharpsl_pm.dev, "Charge Full: Count too low\n"); | ||
373 | schedule_work(&toggle_charger); | ||
374 | } else if (time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_FINISH_TIME)) { | ||
375 | dev_dbg(sharpsl_pm.dev, "Charge Full: Interrupt generated too slowly - retry.\n"); | ||
376 | schedule_work(&toggle_charger); | ||
377 | } else { | ||
378 | sharpsl_charge_off(); | ||
379 | sharpsl_pm.charge_mode = CHRG_DONE; | ||
380 | dev_dbg(sharpsl_pm.dev, "Charge Full: Charging Finished\n"); | ||
381 | } | ||
382 | } | ||
383 | |||
384 | /* Charging Finished Interrupt (Not present on Corgi) */ | ||
385 | /* Can trigger at the same time as an AC staus change so | ||
386 | delay until after that has been processed */ | ||
387 | static irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id, struct pt_regs *fp) | ||
388 | { | ||
389 | if (sharpsl_pm.flags & SHARPSL_SUSPENDED) | ||
390 | return IRQ_HANDLED; | ||
391 | |||
392 | /* delay until after any ac interrupt */ | ||
393 | mod_timer(&sharpsl_pm.chrg_full_timer, jiffies + msecs_to_jiffies(500)); | ||
394 | |||
395 | return IRQ_HANDLED; | ||
396 | } | ||
397 | |||
398 | static irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id, struct pt_regs *fp) | ||
399 | { | ||
400 | int is_fatal = 0; | ||
401 | |||
402 | if (STATUS_BATT_LOCKED == 0) { | ||
403 | dev_err(sharpsl_pm.dev, "Battery now Unlocked! Suspending.\n"); | ||
404 | is_fatal = 1; | ||
405 | } | ||
406 | |||
407 | if (sharpsl_pm.machinfo->gpio_fatal && (STATUS_FATAL == 0)) { | ||
408 | dev_err(sharpsl_pm.dev, "Fatal Batt Error! Suspending.\n"); | ||
409 | is_fatal = 1; | ||
410 | } | ||
411 | |||
412 | if (!(sharpsl_pm.flags & SHARPSL_APM_QUEUED) && is_fatal) { | ||
413 | sharpsl_pm.flags |= SHARPSL_APM_QUEUED; | ||
414 | apm_queue_event(APM_CRITICAL_SUSPEND); | ||
415 | } | ||
416 | |||
417 | return IRQ_HANDLED; | ||
418 | } | ||
419 | |||
420 | /* | ||
421 | * Maintain an average of the last 10 readings | ||
422 | */ | ||
423 | #define SHARPSL_CNV_VALUE_NUM 10 | ||
424 | static int sharpsl_ad_index; | ||
425 | |||
426 | static void sharpsl_average_clear(void) | ||
427 | { | ||
428 | sharpsl_ad_index = 0; | ||
429 | } | ||
430 | |||
431 | static int sharpsl_average_value(int ad) | ||
432 | { | ||
433 | int i, ad_val = 0; | ||
434 | static int sharpsl_ad[SHARPSL_CNV_VALUE_NUM+1]; | ||
435 | |||
436 | if (sharpsl_pm.battstat.mainbat_status != APM_BATTERY_STATUS_HIGH) { | ||
437 | sharpsl_ad_index = 0; | ||
438 | return ad; | ||
439 | } | ||
440 | |||
441 | sharpsl_ad[sharpsl_ad_index] = ad; | ||
442 | sharpsl_ad_index++; | ||
443 | if (sharpsl_ad_index >= SHARPSL_CNV_VALUE_NUM) { | ||
444 | for (i=0; i < (SHARPSL_CNV_VALUE_NUM-1); i++) | ||
445 | sharpsl_ad[i] = sharpsl_ad[i+1]; | ||
446 | sharpsl_ad_index = SHARPSL_CNV_VALUE_NUM - 1; | ||
447 | } | ||
448 | for (i=0; i < sharpsl_ad_index; i++) | ||
449 | ad_val += sharpsl_ad[i]; | ||
450 | |||
451 | return (ad_val / sharpsl_ad_index); | ||
452 | } | ||
453 | |||
454 | |||
455 | /* | ||
456 | * Read MAX1111 ADC | ||
457 | */ | ||
458 | static int read_max1111(int channel) | ||
459 | { | ||
460 | return corgi_ssp_max1111_get((channel << MAXCTRL_SEL_SH) | MAXCTRL_PD0 | MAXCTRL_PD1 | ||
461 | | MAXCTRL_SGL | MAXCTRL_UNI | MAXCTRL_STR); | ||
462 | } | ||
463 | |||
464 | static int sharpsl_read_MainBattery(void) | ||
465 | { | ||
466 | return read_max1111(BATT_AD); | ||
467 | } | ||
468 | |||
469 | static int sharpsl_read_Temp(void) | ||
470 | { | ||
471 | int temp; | ||
472 | |||
473 | sharpsl_pm.machinfo->measure_temp(1); | ||
474 | |||
475 | mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP); | ||
476 | temp = read_max1111(BATT_THM); | ||
477 | |||
478 | sharpsl_pm.machinfo->measure_temp(0); | ||
479 | |||
480 | return temp; | ||
481 | } | ||
482 | |||
483 | static int sharpsl_read_jkvad(void) | ||
484 | { | ||
485 | return read_max1111(JK_VAD); | ||
486 | } | ||
487 | |||
488 | /* | ||
489 | * Take an array of 5 integers, remove the maximum and minimum values | ||
490 | * and return the average. | ||
491 | */ | ||
492 | static int get_select_val(int *val) | ||
493 | { | ||
494 | int i, j, k, temp, sum = 0; | ||
495 | |||
496 | /* Find MAX val */ | ||
497 | temp = val[0]; | ||
498 | j=0; | ||
499 | for (i=1; i<5; i++) { | ||
500 | if (temp < val[i]) { | ||
501 | temp = val[i]; | ||
502 | j = i; | ||
503 | } | ||
504 | } | ||
505 | |||
506 | /* Find MIN val */ | ||
507 | temp = val[4]; | ||
508 | k=4; | ||
509 | for (i=3; i>=0; i--) { | ||
510 | if (temp > val[i]) { | ||
511 | temp = val[i]; | ||
512 | k = i; | ||
513 | } | ||
514 | } | ||
515 | |||
516 | for (i=0; i<5; i++) | ||
517 | if (i != j && i != k ) | ||
518 | sum += val[i]; | ||
519 | |||
520 | dev_dbg(sharpsl_pm.dev, "Average: %d from values: %d, %d, %d, %d, %d\n", sum/3, val[0], val[1], val[2], val[3], val[4]); | ||
521 | |||
522 | return (sum/3); | ||
523 | } | ||
524 | |||
525 | /* mode 0 - Check temperature and voltage | ||
526 | * 1 - Check temperature only */ | ||
527 | static int sharpsl_check_battery(int mode) | ||
528 | { | ||
529 | int val, i, buff[5]; | ||
530 | |||
531 | /* Check battery temperature */ | ||
532 | for (i=0; i<5; i++) { | ||
533 | mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP); | ||
534 | buff[i] = sharpsl_read_Temp(); | ||
535 | } | ||
536 | |||
537 | val = get_select_val(buff); | ||
538 | |||
539 | dev_dbg(sharpsl_pm.dev, "Temperature: %d\n", val); | ||
540 | if (val > SHARPSL_CHARGE_ON_TEMP) | ||
541 | return -1; | ||
542 | if (mode == 1) | ||
543 | return 0; | ||
544 | |||
545 | /* disable charge, enable discharge */ | ||
546 | CHARGE_OFF(); | ||
547 | DISCHARGE_ON(); | ||
548 | mdelay(SHARPSL_WAIT_DISCHARGE_ON); | ||
549 | |||
550 | if (sharpsl_pm.machinfo->discharge1) | ||
551 | sharpsl_pm.machinfo->discharge1(1); | ||
552 | |||
553 | /* Check battery voltage */ | ||
554 | for (i=0; i<5; i++) { | ||
555 | buff[i] = sharpsl_read_MainBattery(); | ||
556 | mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT); | ||
557 | } | ||
558 | |||
559 | if (sharpsl_pm.machinfo->discharge1) | ||
560 | sharpsl_pm.machinfo->discharge1(0); | ||
561 | |||
562 | DISCHARGE_OFF(); | ||
563 | |||
564 | val = get_select_val(buff); | ||
565 | dev_dbg(sharpsl_pm.dev, "Battery Voltage: %d\n", val); | ||
566 | |||
567 | if (val < SHARPSL_CHARGE_ON_VOLT) | ||
568 | return -1; | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | static int sharpsl_ac_check(void) | ||
574 | { | ||
575 | int temp, i, buff[5]; | ||
576 | |||
577 | for (i=0; i<5; i++) { | ||
578 | buff[i] = sharpsl_read_jkvad(); | ||
579 | mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_JKVAD); | ||
580 | } | ||
581 | |||
582 | temp = get_select_val(buff); | ||
583 | dev_dbg(sharpsl_pm.dev, "AC Voltage: %d\n",temp); | ||
584 | |||
585 | if ((temp > SHARPSL_CHARGE_ON_JKVAD_HIGH) || (temp < SHARPSL_CHARGE_ON_JKVAD_LOW)) { | ||
586 | dev_err(sharpsl_pm.dev, "Error: AC check failed.\n"); | ||
587 | return -1; | ||
588 | } | ||
589 | |||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | #ifdef CONFIG_PM | ||
594 | static int sharpsl_pm_suspend(struct device *dev, pm_message_t state) | ||
595 | { | ||
596 | sharpsl_pm.flags |= SHARPSL_SUSPENDED; | ||
597 | flush_scheduled_work(); | ||
598 | |||
599 | if (sharpsl_pm.charge_mode == CHRG_ON) | ||
600 | sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG; | ||
601 | else | ||
602 | sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG; | ||
603 | |||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | static int sharpsl_pm_resume(struct device *dev) | ||
608 | { | ||
609 | /* Clear the reset source indicators as they break the bootloader upon reboot */ | ||
610 | RCSR = 0x0f; | ||
611 | sharpsl_average_clear(); | ||
612 | sharpsl_pm.flags &= ~SHARPSL_APM_QUEUED; | ||
613 | sharpsl_pm.flags &= ~SHARPSL_SUSPENDED; | ||
614 | |||
615 | return 0; | ||
616 | } | ||
617 | |||
618 | static void corgi_goto_sleep(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state) | ||
619 | { | ||
620 | dev_dbg(sharpsl_pm.dev, "Time is: %08x\n",RCNR); | ||
621 | |||
622 | dev_dbg(sharpsl_pm.dev, "Offline Charge Activate = %d\n",sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG); | ||
623 | /* not charging and AC-IN! */ | ||
624 | |||
625 | if ((sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG) && (STATUS_AC_IN != 0)) { | ||
626 | dev_dbg(sharpsl_pm.dev, "Activating Offline Charger...\n"); | ||
627 | sharpsl_pm.charge_mode = CHRG_OFF; | ||
628 | sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG; | ||
629 | sharpsl_off_charge_battery(); | ||
630 | } | ||
631 | |||
632 | sharpsl_pm.machinfo->presuspend(); | ||
633 | |||
634 | PEDR = 0xffffffff; /* clear it */ | ||
635 | |||
636 | sharpsl_pm.flags &= ~SHARPSL_ALARM_ACTIVE; | ||
637 | if ((sharpsl_pm.charge_mode == CHRG_ON) && ((alarm_enable && ((alarm_time - RCNR) > (SHARPSL_BATCHK_TIME_SUSPEND + 30))) || !alarm_enable)) { | ||
638 | RTSR &= RTSR_ALE; | ||
639 | RTAR = RCNR + SHARPSL_BATCHK_TIME_SUSPEND; | ||
640 | dev_dbg(sharpsl_pm.dev, "Charging alarm at: %08x\n",RTAR); | ||
641 | sharpsl_pm.flags |= SHARPSL_ALARM_ACTIVE; | ||
642 | } else if (alarm_enable) { | ||
643 | RTSR &= RTSR_ALE; | ||
644 | RTAR = alarm_time; | ||
645 | dev_dbg(sharpsl_pm.dev, "User alarm at: %08x\n",RTAR); | ||
646 | } else { | ||
647 | dev_dbg(sharpsl_pm.dev, "No alarms set.\n"); | ||
648 | } | ||
649 | |||
650 | pxa_pm_enter(state); | ||
651 | |||
652 | sharpsl_pm.machinfo->postsuspend(); | ||
653 | |||
654 | dev_dbg(sharpsl_pm.dev, "Corgi woken up from suspend: %08x\n",PEDR); | ||
655 | } | ||
656 | |||
657 | static int corgi_enter_suspend(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state) | ||
658 | { | ||
659 | if (!sharpsl_pm.machinfo->should_wakeup(!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE) && alarm_enable) ) | ||
660 | { | ||
661 | if (!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE)) { | ||
662 | dev_dbg(sharpsl_pm.dev, "No user triggered wakeup events and not charging. Strange. Suspend.\n"); | ||
663 | corgi_goto_sleep(alarm_time, alarm_enable, state); | ||
664 | return 1; | ||
665 | } | ||
666 | if(sharpsl_off_charge_battery()) { | ||
667 | dev_dbg(sharpsl_pm.dev, "Charging. Suspend...\n"); | ||
668 | corgi_goto_sleep(alarm_time, alarm_enable, state); | ||
669 | return 1; | ||
670 | } | ||
671 | dev_dbg(sharpsl_pm.dev, "User triggered wakeup in offline charger.\n"); | ||
672 | } | ||
673 | |||
674 | if ((STATUS_BATT_LOCKED == 0) || (sharpsl_fatal_check() < 0) ) | ||
675 | { | ||
676 | dev_err(sharpsl_pm.dev, "Fatal condition. Suspend.\n"); | ||
677 | corgi_goto_sleep(alarm_time, alarm_enable, state); | ||
678 | return 1; | ||
679 | } | ||
680 | |||
681 | return 0; | ||
682 | } | ||
683 | |||
684 | static int corgi_pxa_pm_enter(suspend_state_t state) | ||
685 | { | ||
686 | unsigned long alarm_time = RTAR; | ||
687 | unsigned int alarm_status = ((RTSR & RTSR_ALE) != 0); | ||
688 | |||
689 | dev_dbg(sharpsl_pm.dev, "SharpSL suspending for first time.\n"); | ||
690 | |||
691 | corgi_goto_sleep(alarm_time, alarm_status, state); | ||
692 | |||
693 | while (corgi_enter_suspend(alarm_time,alarm_status,state)) | ||
694 | {} | ||
695 | |||
696 | dev_dbg(sharpsl_pm.dev, "SharpSL resuming...\n"); | ||
697 | |||
698 | return 0; | ||
699 | } | ||
700 | #endif | ||
701 | |||
702 | |||
703 | /* | ||
704 | * Check for fatal battery errors | ||
705 | * Fatal returns -1 | ||
706 | */ | ||
707 | static int sharpsl_fatal_check(void) | ||
708 | { | ||
709 | int buff[5], temp, i, acin; | ||
710 | |||
711 | dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check entered\n"); | ||
712 | |||
713 | /* Check AC-Adapter */ | ||
714 | acin = STATUS_AC_IN; | ||
715 | |||
716 | if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) { | ||
717 | CHARGE_OFF(); | ||
718 | udelay(100); | ||
719 | DISCHARGE_ON(); /* enable discharge */ | ||
720 | mdelay(SHARPSL_WAIT_DISCHARGE_ON); | ||
721 | } | ||
722 | |||
723 | if (sharpsl_pm.machinfo->discharge1) | ||
724 | sharpsl_pm.machinfo->discharge1(1); | ||
725 | |||
726 | /* Check battery : check inserting battery ? */ | ||
727 | for (i=0; i<5; i++) { | ||
728 | buff[i] = sharpsl_read_MainBattery(); | ||
729 | mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT); | ||
730 | } | ||
731 | |||
732 | if (sharpsl_pm.machinfo->discharge1) | ||
733 | sharpsl_pm.machinfo->discharge1(0); | ||
734 | |||
735 | if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) { | ||
736 | udelay(100); | ||
737 | CHARGE_ON(); | ||
738 | DISCHARGE_OFF(); | ||
739 | } | ||
740 | |||
741 | temp = get_select_val(buff); | ||
742 | dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check: acin: %d, discharge voltage: %d, no discharge: %d\n", acin, temp, sharpsl_read_MainBattery()); | ||
743 | |||
744 | if ((acin && (temp < SHARPSL_FATAL_ACIN_VOLT)) || | ||
745 | (!acin && (temp < SHARPSL_FATAL_NOACIN_VOLT))) | ||
746 | return -1; | ||
747 | return 0; | ||
748 | } | ||
749 | |||
750 | static int sharpsl_off_charge_error(void) | ||
751 | { | ||
752 | dev_err(sharpsl_pm.dev, "Offline Charger: Error occured.\n"); | ||
753 | CHARGE_OFF(); | ||
754 | CHARGE_LED_ERR(); | ||
755 | sharpsl_pm.charge_mode = CHRG_ERROR; | ||
756 | return 1; | ||
757 | } | ||
758 | |||
759 | /* | ||
760 | * Charging Control while suspended | ||
761 | * Return 1 - go straight to sleep | ||
762 | * Return 0 - sleep or wakeup depending on other factors | ||
763 | */ | ||
764 | static int sharpsl_off_charge_battery(void) | ||
765 | { | ||
766 | int time; | ||
767 | |||
768 | dev_dbg(sharpsl_pm.dev, "Charge Mode: %d\n", sharpsl_pm.charge_mode); | ||
769 | |||
770 | if (sharpsl_pm.charge_mode == CHRG_OFF) { | ||
771 | dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 1\n"); | ||
772 | |||
773 | /* AC Check */ | ||
774 | if ((sharpsl_ac_check() < 0) || (sharpsl_check_battery(1) < 0)) | ||
775 | return sharpsl_off_charge_error(); | ||
776 | |||
777 | /* Start Charging */ | ||
778 | CHARGE_LED_ON(); | ||
779 | CHARGE_OFF(); | ||
780 | mdelay(SHARPSL_CHARGE_WAIT_TIME); | ||
781 | CHARGE_ON(); | ||
782 | |||
783 | sharpsl_pm.charge_mode = CHRG_ON; | ||
784 | sharpsl_pm.full_count = 0; | ||
785 | |||
786 | return 1; | ||
787 | } else if (sharpsl_pm.charge_mode != CHRG_ON) { | ||
788 | return 1; | ||
789 | } | ||
790 | |||
791 | if (sharpsl_pm.full_count == 0) { | ||
792 | int time; | ||
793 | |||
794 | dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 2\n"); | ||
795 | |||
796 | if (sharpsl_check_battery(0) < 0) | ||
797 | return sharpsl_off_charge_error(); | ||
798 | |||
799 | CHARGE_OFF(); | ||
800 | mdelay(SHARPSL_CHARGE_WAIT_TIME); | ||
801 | CHARGE_ON(); | ||
802 | sharpsl_pm.charge_mode = CHRG_ON; | ||
803 | |||
804 | mdelay(SHARPSL_CHARGE_CO_CHECK_TIME); | ||
805 | |||
806 | time = RCNR; | ||
807 | while(1) { | ||
808 | /* Check if any wakeup event had occured */ | ||
809 | if (sharpsl_pm.machinfo->charger_wakeup() != 0) | ||
810 | return 0; | ||
811 | /* Check for timeout */ | ||
812 | if ((RCNR - time) > SHARPSL_WAIT_CO_TIME) | ||
813 | return 1; | ||
814 | if (STATUS_CHRG_FULL) { | ||
815 | dev_dbg(sharpsl_pm.dev, "Offline Charger: Charge full occured. Retrying to check\n"); | ||
816 | sharpsl_pm.full_count++; | ||
817 | CHARGE_OFF(); | ||
818 | mdelay(SHARPSL_CHARGE_WAIT_TIME); | ||
819 | CHARGE_ON(); | ||
820 | return 1; | ||
821 | } | ||
822 | } | ||
823 | } | ||
824 | |||
825 | dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 3\n"); | ||
826 | |||
827 | mdelay(SHARPSL_CHARGE_CO_CHECK_TIME); | ||
828 | |||
829 | time = RCNR; | ||
830 | while(1) { | ||
831 | /* Check if any wakeup event had occured */ | ||
832 | if (sharpsl_pm.machinfo->charger_wakeup() != 0) | ||
833 | return 0; | ||
834 | /* Check for timeout */ | ||
835 | if ((RCNR-time) > SHARPSL_WAIT_CO_TIME) { | ||
836 | if (sharpsl_pm.full_count > SHARPSL_CHARGE_RETRY_CNT) { | ||
837 | dev_dbg(sharpsl_pm.dev, "Offline Charger: Not charged sufficiently. Retrying.\n"); | ||
838 | sharpsl_pm.full_count = 0; | ||
839 | } | ||
840 | sharpsl_pm.full_count++; | ||
841 | return 1; | ||
842 | } | ||
843 | if (STATUS_CHRG_FULL) { | ||
844 | dev_dbg(sharpsl_pm.dev, "Offline Charger: Charging complete.\n"); | ||
845 | CHARGE_LED_OFF(); | ||
846 | CHARGE_OFF(); | ||
847 | sharpsl_pm.charge_mode = CHRG_DONE; | ||
848 | return 1; | ||
849 | } | ||
850 | } | ||
851 | } | ||
852 | |||
853 | |||
854 | static ssize_t battery_percentage_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
855 | { | ||
856 | return sprintf(buf, "%d\n",sharpsl_pm.battstat.mainbat_percent); | ||
857 | } | ||
858 | |||
859 | static ssize_t battery_voltage_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
860 | { | ||
861 | return sprintf(buf, "%d\n",sharpsl_pm.battstat.mainbat_voltage); | ||
862 | } | ||
863 | |||
864 | static DEVICE_ATTR(battery_percentage, 0444, battery_percentage_show, NULL); | ||
865 | static DEVICE_ATTR(battery_voltage, 0444, battery_voltage_show, NULL); | ||
866 | |||
867 | extern void (*apm_get_power_status)(struct apm_power_info *); | ||
868 | |||
869 | static void sharpsl_apm_get_power_status(struct apm_power_info *info) | ||
870 | { | ||
871 | info->ac_line_status = sharpsl_pm.battstat.ac_status; | ||
872 | |||
873 | if (sharpsl_pm.charge_mode == CHRG_ON) | ||
874 | info->battery_status = APM_BATTERY_STATUS_CHARGING; | ||
875 | else | ||
876 | info->battery_status = sharpsl_pm.battstat.mainbat_status; | ||
877 | |||
878 | info->battery_flag = (1 << info->battery_status); | ||
879 | info->battery_life = sharpsl_pm.battstat.mainbat_percent; | ||
880 | } | ||
881 | |||
882 | static struct pm_ops sharpsl_pm_ops = { | ||
883 | .pm_disk_mode = PM_DISK_FIRMWARE, | ||
884 | .prepare = pxa_pm_prepare, | ||
885 | .enter = corgi_pxa_pm_enter, | ||
886 | .finish = pxa_pm_finish, | ||
887 | }; | ||
888 | |||
889 | static int __init sharpsl_pm_probe(struct device *dev) | ||
890 | { | ||
891 | if (!dev->platform_data) | ||
892 | return -EINVAL; | ||
893 | |||
894 | sharpsl_pm.dev = dev; | ||
895 | sharpsl_pm.machinfo = dev->platform_data; | ||
896 | sharpsl_pm.charge_mode = CHRG_OFF; | ||
897 | sharpsl_pm.flags = 0; | ||
898 | |||
899 | sharpsl_pm.machinfo->init(); | ||
900 | |||
901 | init_timer(&sharpsl_pm.ac_timer); | ||
902 | sharpsl_pm.ac_timer.function = sharpsl_ac_timer; | ||
903 | |||
904 | init_timer(&sharpsl_pm.chrg_full_timer); | ||
905 | sharpsl_pm.chrg_full_timer.function = sharpsl_chrg_full_timer; | ||
906 | |||
907 | pxa_gpio_mode(sharpsl_pm.machinfo->gpio_acin | GPIO_IN); | ||
908 | pxa_gpio_mode(sharpsl_pm.machinfo->gpio_batfull | GPIO_IN); | ||
909 | pxa_gpio_mode(sharpsl_pm.machinfo->gpio_batlock | GPIO_IN); | ||
910 | |||
911 | /* Register interrupt handlers */ | ||
912 | if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin), sharpsl_ac_isr, SA_INTERRUPT, "AC Input Detect", sharpsl_ac_isr)) { | ||
913 | dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin)); | ||
914 | } | ||
915 | else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin),IRQT_BOTHEDGE); | ||
916 | |||
917 | if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock), sharpsl_fatal_isr, SA_INTERRUPT, "Battery Cover", sharpsl_fatal_isr)) { | ||
918 | dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock)); | ||
919 | } | ||
920 | else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock),IRQT_FALLING); | ||
921 | |||
922 | if (sharpsl_pm.machinfo->gpio_fatal) { | ||
923 | if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal), sharpsl_fatal_isr, SA_INTERRUPT, "Fatal Battery", sharpsl_fatal_isr)) { | ||
924 | dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal)); | ||
925 | } | ||
926 | else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal),IRQT_FALLING); | ||
927 | } | ||
928 | |||
929 | if (!machine_is_corgi()) | ||
930 | { | ||
931 | /* Register interrupt handler. */ | ||
932 | if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull), sharpsl_chrg_full_isr, SA_INTERRUPT, "CO", sharpsl_chrg_full_isr)) { | ||
933 | dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull)); | ||
934 | } | ||
935 | else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull),IRQT_RISING); | ||
936 | } | ||
937 | |||
938 | device_create_file(dev, &dev_attr_battery_percentage); | ||
939 | device_create_file(dev, &dev_attr_battery_voltage); | ||
940 | |||
941 | apm_get_power_status = sharpsl_apm_get_power_status; | ||
942 | |||
943 | pm_set_ops(&sharpsl_pm_ops); | ||
944 | |||
945 | mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250)); | ||
946 | |||
947 | return 0; | ||
948 | } | ||
949 | |||
950 | static int sharpsl_pm_remove(struct device *dev) | ||
951 | { | ||
952 | pm_set_ops(NULL); | ||
953 | |||
954 | device_remove_file(dev, &dev_attr_battery_percentage); | ||
955 | device_remove_file(dev, &dev_attr_battery_voltage); | ||
956 | |||
957 | free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin), sharpsl_ac_isr); | ||
958 | free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock), sharpsl_fatal_isr); | ||
959 | |||
960 | if (sharpsl_pm.machinfo->gpio_fatal) | ||
961 | free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal), sharpsl_fatal_isr); | ||
962 | |||
963 | if (!machine_is_corgi()) | ||
964 | free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull), sharpsl_chrg_full_isr); | ||
965 | |||
966 | del_timer_sync(&sharpsl_pm.chrg_full_timer); | ||
967 | del_timer_sync(&sharpsl_pm.ac_timer); | ||
968 | |||
969 | return 0; | ||
970 | } | ||
971 | |||
972 | static struct device_driver sharpsl_pm_driver = { | ||
973 | .name = "sharpsl-pm", | ||
974 | .bus = &platform_bus_type, | ||
975 | .probe = sharpsl_pm_probe, | ||
976 | .remove = sharpsl_pm_remove, | ||
977 | .suspend = sharpsl_pm_suspend, | ||
978 | .resume = sharpsl_pm_resume, | ||
979 | }; | ||
980 | |||
981 | static int __devinit sharpsl_pm_init(void) | ||
982 | { | ||
983 | return driver_register(&sharpsl_pm_driver); | ||
984 | } | ||
985 | |||
986 | static void sharpsl_pm_exit(void) | ||
987 | { | ||
988 | driver_unregister(&sharpsl_pm_driver); | ||
989 | } | ||
990 | |||
991 | late_initcall(sharpsl_pm_init); | ||
992 | module_exit(sharpsl_pm_exit); | ||
diff --git a/arch/arm/mach-pxa/ssp.c b/arch/arm/mach-pxa/ssp.c index 4d826c021315..a68b30eff4d2 100644 --- a/arch/arm/mach-pxa/ssp.c +++ b/arch/arm/mach-pxa/ssp.c | |||
@@ -19,6 +19,8 @@ | |||
19 | * 22nd Aug 2003 Initial version. | 19 | * 22nd Aug 2003 Initial version. |
20 | * 20th Dec 2004 Added ssp_config for changing port config without | 20 | * 20th Dec 2004 Added ssp_config for changing port config without |
21 | * closing the port. | 21 | * closing the port. |
22 | * 4th Aug 2005 Added option to disable irq handler registration and | ||
23 | * cleaned up irq and clock detection. | ||
22 | */ | 24 | */ |
23 | 25 | ||
24 | #include <linux/module.h> | 26 | #include <linux/module.h> |
@@ -37,6 +39,26 @@ | |||
37 | 39 | ||
38 | #define PXA_SSP_PORTS 3 | 40 | #define PXA_SSP_PORTS 3 |
39 | 41 | ||
42 | struct ssp_info_ { | ||
43 | int irq; | ||
44 | u32 clock; | ||
45 | }; | ||
46 | |||
47 | /* | ||
48 | * SSP port clock and IRQ settings | ||
49 | */ | ||
50 | static const struct ssp_info_ ssp_info[PXA_SSP_PORTS] = { | ||
51 | #if defined (CONFIG_PXA27x) | ||
52 | {IRQ_SSP, CKEN23_SSP1}, | ||
53 | {IRQ_SSP2, CKEN3_SSP2}, | ||
54 | {IRQ_SSP3, CKEN4_SSP3}, | ||
55 | #else | ||
56 | {IRQ_SSP, CKEN3_SSP}, | ||
57 | {IRQ_NSSP, CKEN9_NSSP}, | ||
58 | {IRQ_ASSP, CKEN10_ASSP}, | ||
59 | #endif | ||
60 | }; | ||
61 | |||
40 | static DECLARE_MUTEX(sem); | 62 | static DECLARE_MUTEX(sem); |
41 | static int use_count[PXA_SSP_PORTS] = {0, 0, 0}; | 63 | static int use_count[PXA_SSP_PORTS] = {0, 0, 0}; |
42 | 64 | ||
@@ -210,9 +232,9 @@ int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32 psp_flags, u32 spee | |||
210 | * %-EBUSY if the resources are already in use | 232 | * %-EBUSY if the resources are already in use |
211 | * %0 on success | 233 | * %0 on success |
212 | */ | 234 | */ |
213 | int ssp_init(struct ssp_dev *dev, u32 port) | 235 | int ssp_init(struct ssp_dev *dev, u32 port, u32 init_flags) |
214 | { | 236 | { |
215 | int ret, irq; | 237 | int ret; |
216 | 238 | ||
217 | if (port > PXA_SSP_PORTS || port == 0) | 239 | if (port > PXA_SSP_PORTS || port == 0) |
218 | return -ENODEV; | 240 | return -ENODEV; |
@@ -229,61 +251,20 @@ int ssp_init(struct ssp_dev *dev, u32 port) | |||
229 | up(&sem); | 251 | up(&sem); |
230 | return -EBUSY; | 252 | return -EBUSY; |
231 | } | 253 | } |
232 | |||
233 | switch (port) { | ||
234 | case 1: | ||
235 | irq = IRQ_SSP; | ||
236 | break; | ||
237 | #if defined (CONFIG_PXA27x) | ||
238 | case 2: | ||
239 | irq = IRQ_SSP2; | ||
240 | break; | ||
241 | case 3: | ||
242 | irq = IRQ_SSP3; | ||
243 | break; | ||
244 | #else | ||
245 | case 2: | ||
246 | irq = IRQ_NSSP; | ||
247 | break; | ||
248 | case 3: | ||
249 | irq = IRQ_ASSP; | ||
250 | break; | ||
251 | #endif | ||
252 | default: | ||
253 | return -ENODEV; | ||
254 | } | ||
255 | |||
256 | dev->port = port; | 254 | dev->port = port; |
257 | 255 | ||
258 | ret = request_irq(irq, ssp_interrupt, 0, "SSP", dev); | 256 | /* do we need to get irq */ |
259 | if (ret) | 257 | if (!(init_flags & SSP_NO_IRQ)) { |
260 | goto out_region; | 258 | ret = request_irq(ssp_info[port-1].irq, ssp_interrupt, |
259 | 0, "SSP", dev); | ||
260 | if (ret) | ||
261 | goto out_region; | ||
262 | dev->irq = ssp_info[port-1].irq; | ||
263 | } else | ||
264 | dev->irq = 0; | ||
261 | 265 | ||
262 | /* turn on SSP port clock */ | 266 | /* turn on SSP port clock */ |
263 | switch (dev->port) { | 267 | pxa_set_cken(ssp_info[port-1].clock, 1); |
264 | #if defined (CONFIG_PXA27x) | ||
265 | case 1: | ||
266 | pxa_set_cken(CKEN23_SSP1, 1); | ||
267 | break; | ||
268 | case 2: | ||
269 | pxa_set_cken(CKEN3_SSP2, 1); | ||
270 | break; | ||
271 | case 3: | ||
272 | pxa_set_cken(CKEN4_SSP3, 1); | ||
273 | break; | ||
274 | #else | ||
275 | case 1: | ||
276 | pxa_set_cken(CKEN3_SSP, 1); | ||
277 | break; | ||
278 | case 2: | ||
279 | pxa_set_cken(CKEN9_NSSP, 1); | ||
280 | break; | ||
281 | case 3: | ||
282 | pxa_set_cken(CKEN10_ASSP, 1); | ||
283 | break; | ||
284 | #endif | ||
285 | } | ||
286 | |||
287 | up(&sem); | 268 | up(&sem); |
288 | return 0; | 269 | return 0; |
289 | 270 | ||
@@ -301,46 +282,17 @@ out_region: | |||
301 | */ | 282 | */ |
302 | void ssp_exit(struct ssp_dev *dev) | 283 | void ssp_exit(struct ssp_dev *dev) |
303 | { | 284 | { |
304 | int irq; | ||
305 | |||
306 | down(&sem); | 285 | down(&sem); |
307 | SSCR0_P(dev->port) &= ~SSCR0_SSE; | 286 | SSCR0_P(dev->port) &= ~SSCR0_SSE; |
308 | 287 | ||
309 | /* find irq, save power and turn off SSP port clock */ | 288 | if (dev->port > PXA_SSP_PORTS || dev->port == 0) { |
310 | switch (dev->port) { | 289 | printk(KERN_WARNING "SSP: tried to close invalid port\n"); |
311 | #if defined (CONFIG_PXA27x) | 290 | return; |
312 | case 1: | ||
313 | irq = IRQ_SSP; | ||
314 | pxa_set_cken(CKEN23_SSP1, 0); | ||
315 | break; | ||
316 | case 2: | ||
317 | irq = IRQ_SSP2; | ||
318 | pxa_set_cken(CKEN3_SSP2, 0); | ||
319 | break; | ||
320 | case 3: | ||
321 | irq = IRQ_SSP3; | ||
322 | pxa_set_cken(CKEN4_SSP3, 0); | ||
323 | break; | ||
324 | #else | ||
325 | case 1: | ||
326 | irq = IRQ_SSP; | ||
327 | pxa_set_cken(CKEN3_SSP, 0); | ||
328 | break; | ||
329 | case 2: | ||
330 | irq = IRQ_NSSP; | ||
331 | pxa_set_cken(CKEN9_NSSP, 0); | ||
332 | break; | ||
333 | case 3: | ||
334 | irq = IRQ_ASSP; | ||
335 | pxa_set_cken(CKEN10_ASSP, 0); | ||
336 | break; | ||
337 | #endif | ||
338 | default: | ||
339 | printk(KERN_WARNING "SSP: tried to close invalid port\n"); | ||
340 | return; | ||
341 | } | 291 | } |
342 | 292 | ||
343 | free_irq(irq, dev); | 293 | pxa_set_cken(ssp_info[dev->port-1].clock, 0); |
294 | if (dev->irq) | ||
295 | free_irq(dev->irq, dev); | ||
344 | release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c); | 296 | release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c); |
345 | use_count[dev->port - 1]--; | 297 | use_count[dev->port - 1]--; |
346 | up(&sem); | 298 | up(&sem); |
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index e3c14d6b4328..e84fdde6edf8 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig | |||
@@ -102,8 +102,8 @@ config CPU_ARM922T | |||
102 | # ARM925T | 102 | # ARM925T |
103 | config CPU_ARM925T | 103 | config CPU_ARM925T |
104 | bool "Support ARM925T processor" if ARCH_OMAP1 | 104 | bool "Support ARM925T processor" if ARCH_OMAP1 |
105 | depends on ARCH_OMAP1510 | 105 | depends on ARCH_OMAP15XX |
106 | default y if ARCH_OMAP1510 | 106 | default y if ARCH_OMAP15XX |
107 | select CPU_32v4 | 107 | select CPU_32v4 |
108 | select CPU_ABRT_EV4T | 108 | select CPU_ABRT_EV4T |
109 | select CPU_CACHE_V4WT | 109 | select CPU_CACHE_V4WT |
@@ -242,7 +242,7 @@ config CPU_XSCALE | |||
242 | # ARMv6 | 242 | # ARMv6 |
243 | config CPU_V6 | 243 | config CPU_V6 |
244 | bool "Support ARM V6 processor" | 244 | bool "Support ARM V6 processor" |
245 | depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB | 245 | depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP2 |
246 | select CPU_32v6 | 246 | select CPU_32v6 |
247 | select CPU_ABRT_EV6 | 247 | select CPU_ABRT_EV6 |
248 | select CPU_CACHE_V6 | 248 | select CPU_CACHE_V6 |
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile index 7e144f9cad1c..9ccf1943fc94 100644 --- a/arch/arm/plat-omap/Makefile +++ b/arch/arm/plat-omap/Makefile | |||
@@ -3,7 +3,7 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | # Common support | 5 | # Common support |
6 | obj-y := common.o sram.o sram-fn.o clock.o dma.o mux.o gpio.o mcbsp.o usb.o | 6 | obj-y := common.o sram.o sram-fn.o clock.o devices.o dma.o mux.o gpio.o mcbsp.o usb.o |
7 | obj-m := | 7 | obj-m := |
8 | obj-n := | 8 | obj-n := |
9 | obj- := | 9 | obj- := |
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c index a020fe16428f..7ce39b986e23 100644 --- a/arch/arm/plat-omap/clock.c +++ b/arch/arm/plat-omap/clock.c | |||
@@ -1,15 +1,20 @@ | |||
1 | /* | 1 | /* |
2 | * linux/arch/arm/plat-omap/clock.c | 2 | * linux/arch/arm/plat-omap/clock.c |
3 | * | 3 | * |
4 | * Copyright (C) 2004 Nokia corporation | 4 | * Copyright (C) 2004 - 2005 Nokia corporation |
5 | * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> | 5 | * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> |
6 | * | 6 | * |
7 | * Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com> | ||
8 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
9 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
10 | */ | 12 | */ |
11 | #include <linux/module.h> | 13 | #include <linux/version.h> |
14 | #include <linux/config.h> | ||
12 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/init.h> | ||
17 | #include <linux/module.h> | ||
13 | #include <linux/list.h> | 18 | #include <linux/list.h> |
14 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
15 | #include <linux/err.h> | 20 | #include <linux/err.h> |
@@ -18,562 +23,20 @@ | |||
18 | #include <asm/io.h> | 23 | #include <asm/io.h> |
19 | #include <asm/semaphore.h> | 24 | #include <asm/semaphore.h> |
20 | #include <asm/hardware/clock.h> | 25 | #include <asm/hardware/clock.h> |
21 | #include <asm/arch/board.h> | ||
22 | #include <asm/arch/usb.h> | ||
23 | 26 | ||
24 | #include "clock.h" | 27 | #include <asm/arch/clock.h> |
25 | #include "sram.h" | ||
26 | 28 | ||
27 | static LIST_HEAD(clocks); | 29 | LIST_HEAD(clocks); |
28 | static DECLARE_MUTEX(clocks_sem); | 30 | static DECLARE_MUTEX(clocks_sem); |
29 | static DEFINE_SPINLOCK(clockfw_lock); | 31 | DEFINE_SPINLOCK(clockfw_lock); |
30 | static void propagate_rate(struct clk * clk); | ||
31 | /* UART clock function */ | ||
32 | static int set_uart_rate(struct clk * clk, unsigned long rate); | ||
33 | /* External clock (MCLK & BCLK) functions */ | ||
34 | static int set_ext_clk_rate(struct clk * clk, unsigned long rate); | ||
35 | static long round_ext_clk_rate(struct clk * clk, unsigned long rate); | ||
36 | static void init_ext_clk(struct clk * clk); | ||
37 | /* MPU virtual clock functions */ | ||
38 | static int select_table_rate(struct clk * clk, unsigned long rate); | ||
39 | static long round_to_table_rate(struct clk * clk, unsigned long rate); | ||
40 | void clk_setdpll(__u16, __u16); | ||
41 | |||
42 | static struct mpu_rate rate_table[] = { | ||
43 | /* MPU MHz, xtal MHz, dpll1 MHz, CKCTL, DPLL_CTL | ||
44 | * armdiv, dspdiv, dspmmu, tcdiv, perdiv, lcddiv | ||
45 | */ | ||
46 | #if defined(CONFIG_OMAP_ARM_216MHZ) | ||
47 | { 216000000, 12000000, 216000000, 0x050d, 0x2910 }, /* 1/1/2/2/2/8 */ | ||
48 | #endif | ||
49 | #if defined(CONFIG_OMAP_ARM_195MHZ) | ||
50 | { 195000000, 13000000, 195000000, 0x050e, 0x2790 }, /* 1/1/2/2/4/8 */ | ||
51 | #endif | ||
52 | #if defined(CONFIG_OMAP_ARM_192MHZ) | ||
53 | { 192000000, 19200000, 192000000, 0x050f, 0x2510 }, /* 1/1/2/2/8/8 */ | ||
54 | { 192000000, 12000000, 192000000, 0x050f, 0x2810 }, /* 1/1/2/2/8/8 */ | ||
55 | { 96000000, 12000000, 192000000, 0x055f, 0x2810 }, /* 2/2/2/2/8/8 */ | ||
56 | { 48000000, 12000000, 192000000, 0x0baf, 0x2810 }, /* 4/8/4/4/8/8 */ | ||
57 | { 24000000, 12000000, 192000000, 0x0fff, 0x2810 }, /* 8/8/8/8/8/8 */ | ||
58 | #endif | ||
59 | #if defined(CONFIG_OMAP_ARM_182MHZ) | ||
60 | { 182000000, 13000000, 182000000, 0x050e, 0x2710 }, /* 1/1/2/2/4/8 */ | ||
61 | #endif | ||
62 | #if defined(CONFIG_OMAP_ARM_168MHZ) | ||
63 | { 168000000, 12000000, 168000000, 0x010f, 0x2710 }, /* 1/1/1/2/8/8 */ | ||
64 | #endif | ||
65 | #if defined(CONFIG_OMAP_ARM_150MHZ) | ||
66 | { 150000000, 12000000, 150000000, 0x010a, 0x2cb0 }, /* 1/1/1/2/4/4 */ | ||
67 | #endif | ||
68 | #if defined(CONFIG_OMAP_ARM_120MHZ) | ||
69 | { 120000000, 12000000, 120000000, 0x010a, 0x2510 }, /* 1/1/1/2/4/4 */ | ||
70 | #endif | ||
71 | #if defined(CONFIG_OMAP_ARM_96MHZ) | ||
72 | { 96000000, 12000000, 96000000, 0x0005, 0x2410 }, /* 1/1/1/1/2/2 */ | ||
73 | #endif | ||
74 | #if defined(CONFIG_OMAP_ARM_60MHZ) | ||
75 | { 60000000, 12000000, 60000000, 0x0005, 0x2290 }, /* 1/1/1/1/2/2 */ | ||
76 | #endif | ||
77 | #if defined(CONFIG_OMAP_ARM_30MHZ) | ||
78 | { 30000000, 12000000, 60000000, 0x0555, 0x2290 }, /* 2/2/2/2/2/2 */ | ||
79 | #endif | ||
80 | { 0, 0, 0, 0, 0 }, | ||
81 | }; | ||
82 | |||
83 | |||
84 | static void ckctl_recalc(struct clk * clk); | ||
85 | int __clk_enable(struct clk *clk); | ||
86 | void __clk_disable(struct clk *clk); | ||
87 | void __clk_unuse(struct clk *clk); | ||
88 | int __clk_use(struct clk *clk); | ||
89 | |||
90 | |||
91 | static void followparent_recalc(struct clk * clk) | ||
92 | { | ||
93 | clk->rate = clk->parent->rate; | ||
94 | } | ||
95 | |||
96 | |||
97 | static void watchdog_recalc(struct clk * clk) | ||
98 | { | ||
99 | clk->rate = clk->parent->rate / 14; | ||
100 | } | ||
101 | |||
102 | static void uart_recalc(struct clk * clk) | ||
103 | { | ||
104 | unsigned int val = omap_readl(clk->enable_reg); | ||
105 | if (val & clk->enable_bit) | ||
106 | clk->rate = 48000000; | ||
107 | else | ||
108 | clk->rate = 12000000; | ||
109 | } | ||
110 | |||
111 | static struct clk ck_ref = { | ||
112 | .name = "ck_ref", | ||
113 | .rate = 12000000, | ||
114 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
115 | ALWAYS_ENABLED, | ||
116 | }; | ||
117 | |||
118 | static struct clk ck_dpll1 = { | ||
119 | .name = "ck_dpll1", | ||
120 | .parent = &ck_ref, | ||
121 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
122 | RATE_PROPAGATES | ALWAYS_ENABLED, | ||
123 | }; | ||
124 | |||
125 | static struct clk ck_dpll1out = { | ||
126 | .name = "ck_dpll1out", | ||
127 | .parent = &ck_dpll1, | ||
128 | .flags = CLOCK_IN_OMAP16XX, | ||
129 | .enable_reg = ARM_IDLECT2, | ||
130 | .enable_bit = EN_CKOUT_ARM, | ||
131 | .recalc = &followparent_recalc, | ||
132 | }; | ||
133 | |||
134 | static struct clk arm_ck = { | ||
135 | .name = "arm_ck", | ||
136 | .parent = &ck_dpll1, | ||
137 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
138 | RATE_CKCTL | RATE_PROPAGATES | ALWAYS_ENABLED, | ||
139 | .rate_offset = CKCTL_ARMDIV_OFFSET, | ||
140 | .recalc = &ckctl_recalc, | ||
141 | }; | ||
142 | |||
143 | static struct clk armper_ck = { | ||
144 | .name = "armper_ck", | ||
145 | .parent = &ck_dpll1, | ||
146 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
147 | RATE_CKCTL, | ||
148 | .enable_reg = ARM_IDLECT2, | ||
149 | .enable_bit = EN_PERCK, | ||
150 | .rate_offset = CKCTL_PERDIV_OFFSET, | ||
151 | .recalc = &ckctl_recalc, | ||
152 | }; | ||
153 | |||
154 | static struct clk arm_gpio_ck = { | ||
155 | .name = "arm_gpio_ck", | ||
156 | .parent = &ck_dpll1, | ||
157 | .flags = CLOCK_IN_OMAP1510, | ||
158 | .enable_reg = ARM_IDLECT2, | ||
159 | .enable_bit = EN_GPIOCK, | ||
160 | .recalc = &followparent_recalc, | ||
161 | }; | ||
162 | |||
163 | static struct clk armxor_ck = { | ||
164 | .name = "armxor_ck", | ||
165 | .parent = &ck_ref, | ||
166 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, | ||
167 | .enable_reg = ARM_IDLECT2, | ||
168 | .enable_bit = EN_XORPCK, | ||
169 | .recalc = &followparent_recalc, | ||
170 | }; | ||
171 | |||
172 | static struct clk armtim_ck = { | ||
173 | .name = "armtim_ck", | ||
174 | .parent = &ck_ref, | ||
175 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, | ||
176 | .enable_reg = ARM_IDLECT2, | ||
177 | .enable_bit = EN_TIMCK, | ||
178 | .recalc = &followparent_recalc, | ||
179 | }; | ||
180 | |||
181 | static struct clk armwdt_ck = { | ||
182 | .name = "armwdt_ck", | ||
183 | .parent = &ck_ref, | ||
184 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, | ||
185 | .enable_reg = ARM_IDLECT2, | ||
186 | .enable_bit = EN_WDTCK, | ||
187 | .recalc = &watchdog_recalc, | ||
188 | }; | ||
189 | |||
190 | static struct clk arminth_ck16xx = { | ||
191 | .name = "arminth_ck", | ||
192 | .parent = &arm_ck, | ||
193 | .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, | ||
194 | .recalc = &followparent_recalc, | ||
195 | /* Note: On 16xx the frequency can be divided by 2 by programming | ||
196 | * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1 | ||
197 | * | ||
198 | * 1510 version is in TC clocks. | ||
199 | */ | ||
200 | }; | ||
201 | |||
202 | static struct clk dsp_ck = { | ||
203 | .name = "dsp_ck", | ||
204 | .parent = &ck_dpll1, | ||
205 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
206 | RATE_CKCTL, | ||
207 | .enable_reg = ARM_CKCTL, | ||
208 | .enable_bit = EN_DSPCK, | ||
209 | .rate_offset = CKCTL_DSPDIV_OFFSET, | ||
210 | .recalc = &ckctl_recalc, | ||
211 | }; | ||
212 | |||
213 | static struct clk dspmmu_ck = { | ||
214 | .name = "dspmmu_ck", | ||
215 | .parent = &ck_dpll1, | ||
216 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
217 | RATE_CKCTL | ALWAYS_ENABLED, | ||
218 | .rate_offset = CKCTL_DSPMMUDIV_OFFSET, | ||
219 | .recalc = &ckctl_recalc, | ||
220 | }; | ||
221 | |||
222 | static struct clk dspper_ck = { | ||
223 | .name = "dspper_ck", | ||
224 | .parent = &ck_dpll1, | ||
225 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
226 | RATE_CKCTL | DSP_DOMAIN_CLOCK | VIRTUAL_IO_ADDRESS, | ||
227 | .enable_reg = DSP_IDLECT2, | ||
228 | .enable_bit = EN_PERCK, | ||
229 | .rate_offset = CKCTL_PERDIV_OFFSET, | ||
230 | .recalc = &followparent_recalc, | ||
231 | //.recalc = &ckctl_recalc, | ||
232 | }; | ||
233 | |||
234 | static struct clk dspxor_ck = { | ||
235 | .name = "dspxor_ck", | ||
236 | .parent = &ck_ref, | ||
237 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
238 | DSP_DOMAIN_CLOCK | VIRTUAL_IO_ADDRESS, | ||
239 | .enable_reg = DSP_IDLECT2, | ||
240 | .enable_bit = EN_XORPCK, | ||
241 | .recalc = &followparent_recalc, | ||
242 | }; | ||
243 | |||
244 | static struct clk dsptim_ck = { | ||
245 | .name = "dsptim_ck", | ||
246 | .parent = &ck_ref, | ||
247 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
248 | DSP_DOMAIN_CLOCK | VIRTUAL_IO_ADDRESS, | ||
249 | .enable_reg = DSP_IDLECT2, | ||
250 | .enable_bit = EN_DSPTIMCK, | ||
251 | .recalc = &followparent_recalc, | ||
252 | }; | ||
253 | |||
254 | static struct clk tc_ck = { | ||
255 | .name = "tc_ck", | ||
256 | .parent = &ck_dpll1, | ||
257 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730 | | ||
258 | RATE_CKCTL | RATE_PROPAGATES | ALWAYS_ENABLED, | ||
259 | .rate_offset = CKCTL_TCDIV_OFFSET, | ||
260 | .recalc = &ckctl_recalc, | ||
261 | }; | ||
262 | |||
263 | static struct clk arminth_ck1510 = { | ||
264 | .name = "arminth_ck", | ||
265 | .parent = &tc_ck, | ||
266 | .flags = CLOCK_IN_OMAP1510 | ALWAYS_ENABLED, | ||
267 | .recalc = &followparent_recalc, | ||
268 | /* Note: On 1510 the frequency follows TC_CK | ||
269 | * | ||
270 | * 16xx version is in MPU clocks. | ||
271 | */ | ||
272 | }; | ||
273 | |||
274 | static struct clk tipb_ck = { | ||
275 | .name = "tibp_ck", | ||
276 | .parent = &tc_ck, | ||
277 | .flags = CLOCK_IN_OMAP1510 | ALWAYS_ENABLED, | ||
278 | .recalc = &followparent_recalc, | ||
279 | }; | ||
280 | |||
281 | static struct clk l3_ocpi_ck = { | ||
282 | .name = "l3_ocpi_ck", | ||
283 | .parent = &tc_ck, | ||
284 | .flags = CLOCK_IN_OMAP16XX, | ||
285 | .enable_reg = ARM_IDLECT3, | ||
286 | .enable_bit = EN_OCPI_CK, | ||
287 | .recalc = &followparent_recalc, | ||
288 | }; | ||
289 | 32 | ||
290 | static struct clk tc1_ck = { | 33 | static struct clk_functions *arch_clock; |
291 | .name = "tc1_ck", | ||
292 | .parent = &tc_ck, | ||
293 | .flags = CLOCK_IN_OMAP16XX, | ||
294 | .enable_reg = ARM_IDLECT3, | ||
295 | .enable_bit = EN_TC1_CK, | ||
296 | .recalc = &followparent_recalc, | ||
297 | }; | ||
298 | 34 | ||
299 | static struct clk tc2_ck = { | 35 | /*------------------------------------------------------------------------- |
300 | .name = "tc2_ck", | 36 | * Standard clock functions defined in asm/hardware/clock.h |
301 | .parent = &tc_ck, | 37 | *-------------------------------------------------------------------------*/ |
302 | .flags = CLOCK_IN_OMAP16XX, | ||
303 | .enable_reg = ARM_IDLECT3, | ||
304 | .enable_bit = EN_TC2_CK, | ||
305 | .recalc = &followparent_recalc, | ||
306 | }; | ||
307 | 38 | ||
308 | static struct clk dma_ck = { | 39 | struct clk * clk_get(struct device *dev, const char *id) |
309 | .name = "dma_ck", | ||
310 | .parent = &tc_ck, | ||
311 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
312 | ALWAYS_ENABLED, | ||
313 | .recalc = &followparent_recalc, | ||
314 | }; | ||
315 | |||
316 | static struct clk dma_lcdfree_ck = { | ||
317 | .name = "dma_lcdfree_ck", | ||
318 | .parent = &tc_ck, | ||
319 | .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, | ||
320 | .recalc = &followparent_recalc, | ||
321 | }; | ||
322 | |||
323 | static struct clk api_ck = { | ||
324 | .name = "api_ck", | ||
325 | .parent = &tc_ck, | ||
326 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, | ||
327 | .enable_reg = ARM_IDLECT2, | ||
328 | .enable_bit = EN_APICK, | ||
329 | .recalc = &followparent_recalc, | ||
330 | }; | ||
331 | |||
332 | static struct clk lb_ck = { | ||
333 | .name = "lb_ck", | ||
334 | .parent = &tc_ck, | ||
335 | .flags = CLOCK_IN_OMAP1510, | ||
336 | .enable_reg = ARM_IDLECT2, | ||
337 | .enable_bit = EN_LBCK, | ||
338 | .recalc = &followparent_recalc, | ||
339 | }; | ||
340 | |||
341 | static struct clk rhea1_ck = { | ||
342 | .name = "rhea1_ck", | ||
343 | .parent = &tc_ck, | ||
344 | .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, | ||
345 | .recalc = &followparent_recalc, | ||
346 | }; | ||
347 | |||
348 | static struct clk rhea2_ck = { | ||
349 | .name = "rhea2_ck", | ||
350 | .parent = &tc_ck, | ||
351 | .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, | ||
352 | .recalc = &followparent_recalc, | ||
353 | }; | ||
354 | |||
355 | static struct clk lcd_ck = { | ||
356 | .name = "lcd_ck", | ||
357 | .parent = &ck_dpll1, | ||
358 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730 | | ||
359 | RATE_CKCTL, | ||
360 | .enable_reg = ARM_IDLECT2, | ||
361 | .enable_bit = EN_LCDCK, | ||
362 | .rate_offset = CKCTL_LCDDIV_OFFSET, | ||
363 | .recalc = &ckctl_recalc, | ||
364 | }; | ||
365 | |||
366 | static struct clk uart1_1510 = { | ||
367 | .name = "uart1_ck", | ||
368 | /* Direct from ULPD, no parent */ | ||
369 | .rate = 12000000, | ||
370 | .flags = CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | ALWAYS_ENABLED, | ||
371 | .enable_reg = MOD_CONF_CTRL_0, | ||
372 | .enable_bit = 29, /* Chooses between 12MHz and 48MHz */ | ||
373 | .set_rate = &set_uart_rate, | ||
374 | .recalc = &uart_recalc, | ||
375 | }; | ||
376 | |||
377 | static struct clk uart1_16xx = { | ||
378 | .name = "uart1_ck", | ||
379 | /* Direct from ULPD, no parent */ | ||
380 | .rate = 48000000, | ||
381 | .flags = CLOCK_IN_OMAP16XX | RATE_FIXED | ENABLE_REG_32BIT, | ||
382 | .enable_reg = MOD_CONF_CTRL_0, | ||
383 | .enable_bit = 29, | ||
384 | }; | ||
385 | |||
386 | static struct clk uart2_ck = { | ||
387 | .name = "uart2_ck", | ||
388 | /* Direct from ULPD, no parent */ | ||
389 | .rate = 12000000, | ||
390 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | ENABLE_REG_32BIT | | ||
391 | ALWAYS_ENABLED, | ||
392 | .enable_reg = MOD_CONF_CTRL_0, | ||
393 | .enable_bit = 30, /* Chooses between 12MHz and 48MHz */ | ||
394 | .set_rate = &set_uart_rate, | ||
395 | .recalc = &uart_recalc, | ||
396 | }; | ||
397 | |||
398 | static struct clk uart3_1510 = { | ||
399 | .name = "uart3_ck", | ||
400 | /* Direct from ULPD, no parent */ | ||
401 | .rate = 12000000, | ||
402 | .flags = CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | ALWAYS_ENABLED, | ||
403 | .enable_reg = MOD_CONF_CTRL_0, | ||
404 | .enable_bit = 31, /* Chooses between 12MHz and 48MHz */ | ||
405 | .set_rate = &set_uart_rate, | ||
406 | .recalc = &uart_recalc, | ||
407 | }; | ||
408 | |||
409 | static struct clk uart3_16xx = { | ||
410 | .name = "uart3_ck", | ||
411 | /* Direct from ULPD, no parent */ | ||
412 | .rate = 48000000, | ||
413 | .flags = CLOCK_IN_OMAP16XX | RATE_FIXED | ENABLE_REG_32BIT, | ||
414 | .enable_reg = MOD_CONF_CTRL_0, | ||
415 | .enable_bit = 31, | ||
416 | }; | ||
417 | |||
418 | static struct clk usb_clko = { /* 6 MHz output on W4_USB_CLKO */ | ||
419 | .name = "usb_clko", | ||
420 | /* Direct from ULPD, no parent */ | ||
421 | .rate = 6000000, | ||
422 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
423 | RATE_FIXED | ENABLE_REG_32BIT, | ||
424 | .enable_reg = ULPD_CLOCK_CTRL, | ||
425 | .enable_bit = USB_MCLK_EN_BIT, | ||
426 | }; | ||
427 | |||
428 | static struct clk usb_hhc_ck1510 = { | ||
429 | .name = "usb_hhc_ck", | ||
430 | /* Direct from ULPD, no parent */ | ||
431 | .rate = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */ | ||
432 | .flags = CLOCK_IN_OMAP1510 | | ||
433 | RATE_FIXED | ENABLE_REG_32BIT, | ||
434 | .enable_reg = MOD_CONF_CTRL_0, | ||
435 | .enable_bit = USB_HOST_HHC_UHOST_EN, | ||
436 | }; | ||
437 | |||
438 | static struct clk usb_hhc_ck16xx = { | ||
439 | .name = "usb_hhc_ck", | ||
440 | /* Direct from ULPD, no parent */ | ||
441 | .rate = 48000000, | ||
442 | /* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */ | ||
443 | .flags = CLOCK_IN_OMAP16XX | | ||
444 | RATE_FIXED | ENABLE_REG_32BIT, | ||
445 | .enable_reg = OTG_BASE + 0x08 /* OTG_SYSCON_2 */, | ||
446 | .enable_bit = 8 /* UHOST_EN */, | ||
447 | }; | ||
448 | |||
449 | static struct clk usb_dc_ck = { | ||
450 | .name = "usb_dc_ck", | ||
451 | /* Direct from ULPD, no parent */ | ||
452 | .rate = 48000000, | ||
453 | .flags = CLOCK_IN_OMAP16XX | RATE_FIXED, | ||
454 | .enable_reg = SOFT_REQ_REG, | ||
455 | .enable_bit = 4, | ||
456 | }; | ||
457 | |||
458 | static struct clk mclk_1510 = { | ||
459 | .name = "mclk", | ||
460 | /* Direct from ULPD, no parent. May be enabled by ext hardware. */ | ||
461 | .rate = 12000000, | ||
462 | .flags = CLOCK_IN_OMAP1510 | RATE_FIXED, | ||
463 | }; | ||
464 | |||
465 | static struct clk mclk_16xx = { | ||
466 | .name = "mclk", | ||
467 | /* Direct from ULPD, no parent. May be enabled by ext hardware. */ | ||
468 | .flags = CLOCK_IN_OMAP16XX, | ||
469 | .enable_reg = COM_CLK_DIV_CTRL_SEL, | ||
470 | .enable_bit = COM_ULPD_PLL_CLK_REQ, | ||
471 | .set_rate = &set_ext_clk_rate, | ||
472 | .round_rate = &round_ext_clk_rate, | ||
473 | .init = &init_ext_clk, | ||
474 | }; | ||
475 | |||
476 | static struct clk bclk_1510 = { | ||
477 | .name = "bclk", | ||
478 | /* Direct from ULPD, no parent. May be enabled by ext hardware. */ | ||
479 | .rate = 12000000, | ||
480 | .flags = CLOCK_IN_OMAP1510 | RATE_FIXED, | ||
481 | }; | ||
482 | |||
483 | static struct clk bclk_16xx = { | ||
484 | .name = "bclk", | ||
485 | /* Direct from ULPD, no parent. May be enabled by ext hardware. */ | ||
486 | .flags = CLOCK_IN_OMAP16XX, | ||
487 | .enable_reg = SWD_CLK_DIV_CTRL_SEL, | ||
488 | .enable_bit = SWD_ULPD_PLL_CLK_REQ, | ||
489 | .set_rate = &set_ext_clk_rate, | ||
490 | .round_rate = &round_ext_clk_rate, | ||
491 | .init = &init_ext_clk, | ||
492 | }; | ||
493 | |||
494 | static struct clk mmc1_ck = { | ||
495 | .name = "mmc1_ck", | ||
496 | /* Functional clock is direct from ULPD, interface clock is ARMPER */ | ||
497 | .parent = &armper_ck, | ||
498 | .rate = 48000000, | ||
499 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
500 | RATE_FIXED | ENABLE_REG_32BIT, | ||
501 | .enable_reg = MOD_CONF_CTRL_0, | ||
502 | .enable_bit = 23, | ||
503 | }; | ||
504 | |||
505 | static struct clk mmc2_ck = { | ||
506 | .name = "mmc2_ck", | ||
507 | /* Functional clock is direct from ULPD, interface clock is ARMPER */ | ||
508 | .parent = &armper_ck, | ||
509 | .rate = 48000000, | ||
510 | .flags = CLOCK_IN_OMAP16XX | | ||
511 | RATE_FIXED | ENABLE_REG_32BIT, | ||
512 | .enable_reg = MOD_CONF_CTRL_0, | ||
513 | .enable_bit = 20, | ||
514 | }; | ||
515 | |||
516 | static struct clk virtual_ck_mpu = { | ||
517 | .name = "mpu", | ||
518 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
519 | VIRTUAL_CLOCK | ALWAYS_ENABLED, | ||
520 | .parent = &arm_ck, /* Is smarter alias for */ | ||
521 | .recalc = &followparent_recalc, | ||
522 | .set_rate = &select_table_rate, | ||
523 | .round_rate = &round_to_table_rate, | ||
524 | }; | ||
525 | |||
526 | |||
527 | static struct clk * onchip_clks[] = { | ||
528 | /* non-ULPD clocks */ | ||
529 | &ck_ref, | ||
530 | &ck_dpll1, | ||
531 | /* CK_GEN1 clocks */ | ||
532 | &ck_dpll1out, | ||
533 | &arm_ck, | ||
534 | &armper_ck, | ||
535 | &arm_gpio_ck, | ||
536 | &armxor_ck, | ||
537 | &armtim_ck, | ||
538 | &armwdt_ck, | ||
539 | &arminth_ck1510, &arminth_ck16xx, | ||
540 | /* CK_GEN2 clocks */ | ||
541 | &dsp_ck, | ||
542 | &dspmmu_ck, | ||
543 | &dspper_ck, | ||
544 | &dspxor_ck, | ||
545 | &dsptim_ck, | ||
546 | /* CK_GEN3 clocks */ | ||
547 | &tc_ck, | ||
548 | &tipb_ck, | ||
549 | &l3_ocpi_ck, | ||
550 | &tc1_ck, | ||
551 | &tc2_ck, | ||
552 | &dma_ck, | ||
553 | &dma_lcdfree_ck, | ||
554 | &api_ck, | ||
555 | &lb_ck, | ||
556 | &rhea1_ck, | ||
557 | &rhea2_ck, | ||
558 | &lcd_ck, | ||
559 | /* ULPD clocks */ | ||
560 | &uart1_1510, | ||
561 | &uart1_16xx, | ||
562 | &uart2_ck, | ||
563 | &uart3_1510, | ||
564 | &uart3_16xx, | ||
565 | &usb_clko, | ||
566 | &usb_hhc_ck1510, &usb_hhc_ck16xx, | ||
567 | &usb_dc_ck, | ||
568 | &mclk_1510, &mclk_16xx, | ||
569 | &bclk_1510, &bclk_16xx, | ||
570 | &mmc1_ck, | ||
571 | &mmc2_ck, | ||
572 | /* Virtual clocks */ | ||
573 | &virtual_ck_mpu, | ||
574 | }; | ||
575 | |||
576 | struct clk *clk_get(struct device *dev, const char *id) | ||
577 | { | 40 | { |
578 | struct clk *p, *clk = ERR_PTR(-ENOENT); | 41 | struct clk *p, *clk = ERR_PTR(-ENOENT); |
579 | 42 | ||
@@ -590,534 +53,200 @@ struct clk *clk_get(struct device *dev, const char *id) | |||
590 | } | 53 | } |
591 | EXPORT_SYMBOL(clk_get); | 54 | EXPORT_SYMBOL(clk_get); |
592 | 55 | ||
593 | |||
594 | void clk_put(struct clk *clk) | ||
595 | { | ||
596 | if (clk && !IS_ERR(clk)) | ||
597 | module_put(clk->owner); | ||
598 | } | ||
599 | EXPORT_SYMBOL(clk_put); | ||
600 | |||
601 | |||
602 | int __clk_enable(struct clk *clk) | ||
603 | { | ||
604 | __u16 regval16; | ||
605 | __u32 regval32; | ||
606 | |||
607 | if (clk->flags & ALWAYS_ENABLED) | ||
608 | return 0; | ||
609 | |||
610 | if (unlikely(clk->enable_reg == 0)) { | ||
611 | printk(KERN_ERR "clock.c: Enable for %s without enable code\n", | ||
612 | clk->name); | ||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | if (clk->flags & DSP_DOMAIN_CLOCK) { | ||
617 | __clk_use(&api_ck); | ||
618 | } | ||
619 | |||
620 | if (clk->flags & ENABLE_REG_32BIT) { | ||
621 | if (clk->flags & VIRTUAL_IO_ADDRESS) { | ||
622 | regval32 = __raw_readl(clk->enable_reg); | ||
623 | regval32 |= (1 << clk->enable_bit); | ||
624 | __raw_writel(regval32, clk->enable_reg); | ||
625 | } else { | ||
626 | regval32 = omap_readl(clk->enable_reg); | ||
627 | regval32 |= (1 << clk->enable_bit); | ||
628 | omap_writel(regval32, clk->enable_reg); | ||
629 | } | ||
630 | } else { | ||
631 | if (clk->flags & VIRTUAL_IO_ADDRESS) { | ||
632 | regval16 = __raw_readw(clk->enable_reg); | ||
633 | regval16 |= (1 << clk->enable_bit); | ||
634 | __raw_writew(regval16, clk->enable_reg); | ||
635 | } else { | ||
636 | regval16 = omap_readw(clk->enable_reg); | ||
637 | regval16 |= (1 << clk->enable_bit); | ||
638 | omap_writew(regval16, clk->enable_reg); | ||
639 | } | ||
640 | } | ||
641 | |||
642 | if (clk->flags & DSP_DOMAIN_CLOCK) { | ||
643 | __clk_unuse(&api_ck); | ||
644 | } | ||
645 | |||
646 | return 0; | ||
647 | } | ||
648 | |||
649 | |||
650 | void __clk_disable(struct clk *clk) | ||
651 | { | ||
652 | __u16 regval16; | ||
653 | __u32 regval32; | ||
654 | |||
655 | if (clk->enable_reg == 0) | ||
656 | return; | ||
657 | |||
658 | if (clk->flags & DSP_DOMAIN_CLOCK) { | ||
659 | __clk_use(&api_ck); | ||
660 | } | ||
661 | |||
662 | if (clk->flags & ENABLE_REG_32BIT) { | ||
663 | if (clk->flags & VIRTUAL_IO_ADDRESS) { | ||
664 | regval32 = __raw_readl(clk->enable_reg); | ||
665 | regval32 &= ~(1 << clk->enable_bit); | ||
666 | __raw_writel(regval32, clk->enable_reg); | ||
667 | } else { | ||
668 | regval32 = omap_readl(clk->enable_reg); | ||
669 | regval32 &= ~(1 << clk->enable_bit); | ||
670 | omap_writel(regval32, clk->enable_reg); | ||
671 | } | ||
672 | } else { | ||
673 | if (clk->flags & VIRTUAL_IO_ADDRESS) { | ||
674 | regval16 = __raw_readw(clk->enable_reg); | ||
675 | regval16 &= ~(1 << clk->enable_bit); | ||
676 | __raw_writew(regval16, clk->enable_reg); | ||
677 | } else { | ||
678 | regval16 = omap_readw(clk->enable_reg); | ||
679 | regval16 &= ~(1 << clk->enable_bit); | ||
680 | omap_writew(regval16, clk->enable_reg); | ||
681 | } | ||
682 | } | ||
683 | |||
684 | if (clk->flags & DSP_DOMAIN_CLOCK) { | ||
685 | __clk_unuse(&api_ck); | ||
686 | } | ||
687 | } | ||
688 | |||
689 | |||
690 | void __clk_unuse(struct clk *clk) | ||
691 | { | ||
692 | if (clk->usecount > 0 && !(--clk->usecount)) { | ||
693 | __clk_disable(clk); | ||
694 | if (likely(clk->parent)) | ||
695 | __clk_unuse(clk->parent); | ||
696 | } | ||
697 | } | ||
698 | |||
699 | |||
700 | int __clk_use(struct clk *clk) | ||
701 | { | ||
702 | int ret = 0; | ||
703 | if (clk->usecount++ == 0) { | ||
704 | if (likely(clk->parent)) | ||
705 | ret = __clk_use(clk->parent); | ||
706 | |||
707 | if (unlikely(ret != 0)) { | ||
708 | clk->usecount--; | ||
709 | return ret; | ||
710 | } | ||
711 | |||
712 | ret = __clk_enable(clk); | ||
713 | |||
714 | if (unlikely(ret != 0) && clk->parent) { | ||
715 | __clk_unuse(clk->parent); | ||
716 | clk->usecount--; | ||
717 | } | ||
718 | } | ||
719 | |||
720 | return ret; | ||
721 | } | ||
722 | |||
723 | |||
724 | int clk_enable(struct clk *clk) | 56 | int clk_enable(struct clk *clk) |
725 | { | 57 | { |
726 | unsigned long flags; | 58 | unsigned long flags; |
727 | int ret; | 59 | int ret = 0; |
728 | 60 | ||
729 | spin_lock_irqsave(&clockfw_lock, flags); | 61 | spin_lock_irqsave(&clockfw_lock, flags); |
730 | ret = __clk_enable(clk); | 62 | if (clk->enable) |
63 | ret = clk->enable(clk); | ||
64 | else if (arch_clock->clk_enable) | ||
65 | ret = arch_clock->clk_enable(clk); | ||
66 | else | ||
67 | printk(KERN_ERR "Could not enable clock %s\n", clk->name); | ||
731 | spin_unlock_irqrestore(&clockfw_lock, flags); | 68 | spin_unlock_irqrestore(&clockfw_lock, flags); |
69 | |||
732 | return ret; | 70 | return ret; |
733 | } | 71 | } |
734 | EXPORT_SYMBOL(clk_enable); | 72 | EXPORT_SYMBOL(clk_enable); |
735 | 73 | ||
736 | |||
737 | void clk_disable(struct clk *clk) | 74 | void clk_disable(struct clk *clk) |
738 | { | 75 | { |
739 | unsigned long flags; | 76 | unsigned long flags; |
740 | 77 | ||
741 | spin_lock_irqsave(&clockfw_lock, flags); | 78 | spin_lock_irqsave(&clockfw_lock, flags); |
742 | __clk_disable(clk); | 79 | if (clk->disable) |
80 | clk->disable(clk); | ||
81 | else if (arch_clock->clk_disable) | ||
82 | arch_clock->clk_disable(clk); | ||
83 | else | ||
84 | printk(KERN_ERR "Could not disable clock %s\n", clk->name); | ||
743 | spin_unlock_irqrestore(&clockfw_lock, flags); | 85 | spin_unlock_irqrestore(&clockfw_lock, flags); |
744 | } | 86 | } |
745 | EXPORT_SYMBOL(clk_disable); | 87 | EXPORT_SYMBOL(clk_disable); |
746 | 88 | ||
747 | |||
748 | int clk_use(struct clk *clk) | 89 | int clk_use(struct clk *clk) |
749 | { | 90 | { |
750 | unsigned long flags; | 91 | unsigned long flags; |
751 | int ret = 0; | 92 | int ret = 0; |
752 | 93 | ||
753 | spin_lock_irqsave(&clockfw_lock, flags); | 94 | spin_lock_irqsave(&clockfw_lock, flags); |
754 | ret = __clk_use(clk); | 95 | if (arch_clock->clk_use) |
96 | ret = arch_clock->clk_use(clk); | ||
755 | spin_unlock_irqrestore(&clockfw_lock, flags); | 97 | spin_unlock_irqrestore(&clockfw_lock, flags); |
98 | |||
756 | return ret; | 99 | return ret; |
757 | } | 100 | } |
758 | EXPORT_SYMBOL(clk_use); | 101 | EXPORT_SYMBOL(clk_use); |
759 | 102 | ||
760 | |||
761 | void clk_unuse(struct clk *clk) | 103 | void clk_unuse(struct clk *clk) |
762 | { | 104 | { |
763 | unsigned long flags; | 105 | unsigned long flags; |
764 | 106 | ||
765 | spin_lock_irqsave(&clockfw_lock, flags); | 107 | spin_lock_irqsave(&clockfw_lock, flags); |
766 | __clk_unuse(clk); | 108 | if (arch_clock->clk_unuse) |
109 | arch_clock->clk_unuse(clk); | ||
767 | spin_unlock_irqrestore(&clockfw_lock, flags); | 110 | spin_unlock_irqrestore(&clockfw_lock, flags); |
768 | } | 111 | } |
769 | EXPORT_SYMBOL(clk_unuse); | 112 | EXPORT_SYMBOL(clk_unuse); |
770 | 113 | ||
771 | |||
772 | int clk_get_usecount(struct clk *clk) | 114 | int clk_get_usecount(struct clk *clk) |
773 | { | 115 | { |
774 | return clk->usecount; | 116 | unsigned long flags; |
775 | } | 117 | int ret = 0; |
776 | EXPORT_SYMBOL(clk_get_usecount); | ||
777 | |||
778 | |||
779 | unsigned long clk_get_rate(struct clk *clk) | ||
780 | { | ||
781 | return clk->rate; | ||
782 | } | ||
783 | EXPORT_SYMBOL(clk_get_rate); | ||
784 | |||
785 | |||
786 | static __u16 verify_ckctl_value(__u16 newval) | ||
787 | { | ||
788 | /* This function checks for following limitations set | ||
789 | * by the hardware (all conditions must be true): | ||
790 | * DSPMMU_CK == DSP_CK or DSPMMU_CK == DSP_CK/2 | ||
791 | * ARM_CK >= TC_CK | ||
792 | * DSP_CK >= TC_CK | ||
793 | * DSPMMU_CK >= TC_CK | ||
794 | * | ||
795 | * In addition following rules are enforced: | ||
796 | * LCD_CK <= TC_CK | ||
797 | * ARMPER_CK <= TC_CK | ||
798 | * | ||
799 | * However, maximum frequencies are not checked for! | ||
800 | */ | ||
801 | __u8 per_exp; | ||
802 | __u8 lcd_exp; | ||
803 | __u8 arm_exp; | ||
804 | __u8 dsp_exp; | ||
805 | __u8 tc_exp; | ||
806 | __u8 dspmmu_exp; | ||
807 | |||
808 | per_exp = (newval >> CKCTL_PERDIV_OFFSET) & 3; | ||
809 | lcd_exp = (newval >> CKCTL_LCDDIV_OFFSET) & 3; | ||
810 | arm_exp = (newval >> CKCTL_ARMDIV_OFFSET) & 3; | ||
811 | dsp_exp = (newval >> CKCTL_DSPDIV_OFFSET) & 3; | ||
812 | tc_exp = (newval >> CKCTL_TCDIV_OFFSET) & 3; | ||
813 | dspmmu_exp = (newval >> CKCTL_DSPMMUDIV_OFFSET) & 3; | ||
814 | |||
815 | if (dspmmu_exp < dsp_exp) | ||
816 | dspmmu_exp = dsp_exp; | ||
817 | if (dspmmu_exp > dsp_exp+1) | ||
818 | dspmmu_exp = dsp_exp+1; | ||
819 | if (tc_exp < arm_exp) | ||
820 | tc_exp = arm_exp; | ||
821 | if (tc_exp < dspmmu_exp) | ||
822 | tc_exp = dspmmu_exp; | ||
823 | if (tc_exp > lcd_exp) | ||
824 | lcd_exp = tc_exp; | ||
825 | if (tc_exp > per_exp) | ||
826 | per_exp = tc_exp; | ||
827 | 118 | ||
828 | newval &= 0xf000; | 119 | spin_lock_irqsave(&clockfw_lock, flags); |
829 | newval |= per_exp << CKCTL_PERDIV_OFFSET; | 120 | ret = clk->usecount; |
830 | newval |= lcd_exp << CKCTL_LCDDIV_OFFSET; | 121 | spin_unlock_irqrestore(&clockfw_lock, flags); |
831 | newval |= arm_exp << CKCTL_ARMDIV_OFFSET; | ||
832 | newval |= dsp_exp << CKCTL_DSPDIV_OFFSET; | ||
833 | newval |= tc_exp << CKCTL_TCDIV_OFFSET; | ||
834 | newval |= dspmmu_exp << CKCTL_DSPMMUDIV_OFFSET; | ||
835 | 122 | ||
836 | return newval; | 123 | return ret; |
837 | } | 124 | } |
125 | EXPORT_SYMBOL(clk_get_usecount); | ||
838 | 126 | ||
839 | 127 | unsigned long clk_get_rate(struct clk *clk) | |
840 | static int calc_dsor_exp(struct clk *clk, unsigned long rate) | ||
841 | { | 128 | { |
842 | /* Note: If target frequency is too low, this function will return 4, | 129 | unsigned long flags; |
843 | * which is invalid value. Caller must check for this value and act | 130 | unsigned long ret = 0; |
844 | * accordingly. | ||
845 | * | ||
846 | * Note: This function does not check for following limitations set | ||
847 | * by the hardware (all conditions must be true): | ||
848 | * DSPMMU_CK == DSP_CK or DSPMMU_CK == DSP_CK/2 | ||
849 | * ARM_CK >= TC_CK | ||
850 | * DSP_CK >= TC_CK | ||
851 | * DSPMMU_CK >= TC_CK | ||
852 | */ | ||
853 | unsigned long realrate; | ||
854 | struct clk * parent; | ||
855 | unsigned dsor_exp; | ||
856 | |||
857 | if (unlikely(!(clk->flags & RATE_CKCTL))) | ||
858 | return -EINVAL; | ||
859 | |||
860 | parent = clk->parent; | ||
861 | if (unlikely(parent == 0)) | ||
862 | return -EIO; | ||
863 | |||
864 | realrate = parent->rate; | ||
865 | for (dsor_exp=0; dsor_exp<4; dsor_exp++) { | ||
866 | if (realrate <= rate) | ||
867 | break; | ||
868 | 131 | ||
869 | realrate /= 2; | 132 | spin_lock_irqsave(&clockfw_lock, flags); |
870 | } | 133 | ret = clk->rate; |
134 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
871 | 135 | ||
872 | return dsor_exp; | 136 | return ret; |
873 | } | 137 | } |
138 | EXPORT_SYMBOL(clk_get_rate); | ||
874 | 139 | ||
875 | 140 | void clk_put(struct clk *clk) | |
876 | static void ckctl_recalc(struct clk * clk) | ||
877 | { | 141 | { |
878 | int dsor; | 142 | if (clk && !IS_ERR(clk)) |
879 | 143 | module_put(clk->owner); | |
880 | /* Calculate divisor encoded as 2-bit exponent */ | ||
881 | if (clk->flags & DSP_DOMAIN_CLOCK) { | ||
882 | /* The clock control bits are in DSP domain, | ||
883 | * so api_ck is needed for access. | ||
884 | * Note that DSP_CKCTL virt addr = phys addr, so | ||
885 | * we must use __raw_readw() instead of omap_readw(). | ||
886 | */ | ||
887 | __clk_use(&api_ck); | ||
888 | dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset)); | ||
889 | __clk_unuse(&api_ck); | ||
890 | } else { | ||
891 | dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset)); | ||
892 | } | ||
893 | if (unlikely(clk->rate == clk->parent->rate / dsor)) | ||
894 | return; /* No change, quick exit */ | ||
895 | clk->rate = clk->parent->rate / dsor; | ||
896 | |||
897 | if (unlikely(clk->flags & RATE_PROPAGATES)) | ||
898 | propagate_rate(clk); | ||
899 | } | 144 | } |
145 | EXPORT_SYMBOL(clk_put); | ||
900 | 146 | ||
147 | /*------------------------------------------------------------------------- | ||
148 | * Optional clock functions defined in asm/hardware/clock.h | ||
149 | *-------------------------------------------------------------------------*/ | ||
901 | 150 | ||
902 | long clk_round_rate(struct clk *clk, unsigned long rate) | 151 | long clk_round_rate(struct clk *clk, unsigned long rate) |
903 | { | 152 | { |
904 | int dsor_exp; | 153 | unsigned long flags; |
905 | 154 | long ret = 0; | |
906 | if (clk->flags & RATE_FIXED) | ||
907 | return clk->rate; | ||
908 | |||
909 | if (clk->flags & RATE_CKCTL) { | ||
910 | dsor_exp = calc_dsor_exp(clk, rate); | ||
911 | if (dsor_exp < 0) | ||
912 | return dsor_exp; | ||
913 | if (dsor_exp > 3) | ||
914 | dsor_exp = 3; | ||
915 | return clk->parent->rate / (1 << dsor_exp); | ||
916 | } | ||
917 | 155 | ||
918 | if(clk->round_rate != 0) | 156 | spin_lock_irqsave(&clockfw_lock, flags); |
919 | return clk->round_rate(clk, rate); | 157 | if (arch_clock->clk_round_rate) |
158 | ret = arch_clock->clk_round_rate(clk, rate); | ||
159 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
920 | 160 | ||
921 | return clk->rate; | 161 | return ret; |
922 | } | 162 | } |
923 | EXPORT_SYMBOL(clk_round_rate); | 163 | EXPORT_SYMBOL(clk_round_rate); |
924 | 164 | ||
925 | 165 | int clk_set_rate(struct clk *clk, unsigned long rate) | |
926 | static void propagate_rate(struct clk * clk) | ||
927 | { | ||
928 | struct clk ** clkp; | ||
929 | |||
930 | for (clkp = onchip_clks; clkp < onchip_clks+ARRAY_SIZE(onchip_clks); clkp++) { | ||
931 | if (likely((*clkp)->parent != clk)) continue; | ||
932 | if (likely((*clkp)->recalc)) | ||
933 | (*clkp)->recalc(*clkp); | ||
934 | } | ||
935 | } | ||
936 | |||
937 | |||
938 | static int select_table_rate(struct clk * clk, unsigned long rate) | ||
939 | { | 166 | { |
940 | /* Find the highest supported frequency <= rate and switch to it */ | 167 | unsigned long flags; |
941 | struct mpu_rate * ptr; | 168 | int ret = 0; |
942 | |||
943 | if (clk != &virtual_ck_mpu) | ||
944 | return -EINVAL; | ||
945 | |||
946 | for (ptr = rate_table; ptr->rate; ptr++) { | ||
947 | if (ptr->xtal != ck_ref.rate) | ||
948 | continue; | ||
949 | |||
950 | /* DPLL1 cannot be reprogrammed without risking system crash */ | ||
951 | if (likely(ck_dpll1.rate!=0) && ptr->pll_rate != ck_dpll1.rate) | ||
952 | continue; | ||
953 | |||
954 | /* Can check only after xtal frequency check */ | ||
955 | if (ptr->rate <= rate) | ||
956 | break; | ||
957 | } | ||
958 | |||
959 | if (!ptr->rate) | ||
960 | return -EINVAL; | ||
961 | 169 | ||
962 | /* | 170 | spin_lock_irqsave(&clockfw_lock, flags); |
963 | * In most cases we should not need to reprogram DPLL. | 171 | if (arch_clock->clk_set_rate) |
964 | * Reprogramming the DPLL is tricky, it must be done from SRAM. | 172 | ret = arch_clock->clk_set_rate(clk, rate); |
965 | */ | 173 | spin_unlock_irqrestore(&clockfw_lock, flags); |
966 | omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val); | ||
967 | 174 | ||
968 | ck_dpll1.rate = ptr->pll_rate; | 175 | return ret; |
969 | propagate_rate(&ck_dpll1); | ||
970 | return 0; | ||
971 | } | 176 | } |
177 | EXPORT_SYMBOL(clk_set_rate); | ||
972 | 178 | ||
973 | 179 | int clk_set_parent(struct clk *clk, struct clk *parent) | |
974 | static long round_to_table_rate(struct clk * clk, unsigned long rate) | ||
975 | { | 180 | { |
976 | /* Find the highest supported frequency <= rate */ | 181 | unsigned long flags; |
977 | struct mpu_rate * ptr; | 182 | int ret = 0; |
978 | long highest_rate; | ||
979 | |||
980 | if (clk != &virtual_ck_mpu) | ||
981 | return -EINVAL; | ||
982 | |||
983 | highest_rate = -EINVAL; | ||
984 | |||
985 | for (ptr = rate_table; ptr->rate; ptr++) { | ||
986 | if (ptr->xtal != ck_ref.rate) | ||
987 | continue; | ||
988 | |||
989 | highest_rate = ptr->rate; | ||
990 | 183 | ||
991 | /* Can check only after xtal frequency check */ | 184 | spin_lock_irqsave(&clockfw_lock, flags); |
992 | if (ptr->rate <= rate) | 185 | if (arch_clock->clk_set_parent) |
993 | break; | 186 | ret = arch_clock->clk_set_parent(clk, parent); |
994 | } | 187 | spin_unlock_irqrestore(&clockfw_lock, flags); |
995 | 188 | ||
996 | return highest_rate; | 189 | return ret; |
997 | } | 190 | } |
191 | EXPORT_SYMBOL(clk_set_parent); | ||
998 | 192 | ||
999 | 193 | struct clk *clk_get_parent(struct clk *clk) | |
1000 | int clk_set_rate(struct clk *clk, unsigned long rate) | ||
1001 | { | 194 | { |
1002 | int ret = -EINVAL; | 195 | unsigned long flags; |
1003 | int dsor_exp; | 196 | struct clk * ret = NULL; |
1004 | __u16 regval; | ||
1005 | unsigned long flags; | ||
1006 | |||
1007 | if (clk->flags & RATE_CKCTL) { | ||
1008 | dsor_exp = calc_dsor_exp(clk, rate); | ||
1009 | if (dsor_exp > 3) | ||
1010 | dsor_exp = -EINVAL; | ||
1011 | if (dsor_exp < 0) | ||
1012 | return dsor_exp; | ||
1013 | |||
1014 | spin_lock_irqsave(&clockfw_lock, flags); | ||
1015 | regval = omap_readw(ARM_CKCTL); | ||
1016 | regval &= ~(3 << clk->rate_offset); | ||
1017 | regval |= dsor_exp << clk->rate_offset; | ||
1018 | regval = verify_ckctl_value(regval); | ||
1019 | omap_writew(regval, ARM_CKCTL); | ||
1020 | clk->rate = clk->parent->rate / (1 << dsor_exp); | ||
1021 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
1022 | ret = 0; | ||
1023 | } else if(clk->set_rate != 0) { | ||
1024 | spin_lock_irqsave(&clockfw_lock, flags); | ||
1025 | ret = clk->set_rate(clk, rate); | ||
1026 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
1027 | } | ||
1028 | 197 | ||
1029 | if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES))) | 198 | spin_lock_irqsave(&clockfw_lock, flags); |
1030 | propagate_rate(clk); | 199 | if (arch_clock->clk_get_parent) |
200 | ret = arch_clock->clk_get_parent(clk); | ||
201 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
1031 | 202 | ||
1032 | return ret; | 203 | return ret; |
1033 | } | 204 | } |
1034 | EXPORT_SYMBOL(clk_set_rate); | 205 | EXPORT_SYMBOL(clk_get_parent); |
1035 | 206 | ||
207 | /*------------------------------------------------------------------------- | ||
208 | * OMAP specific clock functions shared between omap1 and omap2 | ||
209 | *-------------------------------------------------------------------------*/ | ||
1036 | 210 | ||
1037 | static unsigned calc_ext_dsor(unsigned long rate) | 211 | unsigned int __initdata mpurate; |
1038 | { | ||
1039 | unsigned dsor; | ||
1040 | 212 | ||
1041 | /* MCLK and BCLK divisor selection is not linear: | 213 | /* |
1042 | * freq = 96MHz / dsor | 214 | * By default we use the rate set by the bootloader. |
1043 | * | 215 | * You can override this with mpurate= cmdline option. |
1044 | * RATIO_SEL range: dsor <-> RATIO_SEL | 216 | */ |
1045 | * 0..6: (RATIO_SEL+2) <-> (dsor-2) | 217 | static int __init omap_clk_setup(char *str) |
1046 | * 6..48: (8+(RATIO_SEL-6)*2) <-> ((dsor-8)/2+6) | ||
1047 | * Minimum dsor is 2 and maximum is 96. Odd divisors starting from 9 | ||
1048 | * can not be used. | ||
1049 | */ | ||
1050 | for (dsor = 2; dsor < 96; ++dsor) { | ||
1051 | if ((dsor & 1) && dsor > 8) | ||
1052 | continue; | ||
1053 | if (rate >= 96000000 / dsor) | ||
1054 | break; | ||
1055 | } | ||
1056 | return dsor; | ||
1057 | } | ||
1058 | |||
1059 | /* Only needed on 1510 */ | ||
1060 | static int set_uart_rate(struct clk * clk, unsigned long rate) | ||
1061 | { | ||
1062 | unsigned int val; | ||
1063 | |||
1064 | val = omap_readl(clk->enable_reg); | ||
1065 | if (rate == 12000000) | ||
1066 | val &= ~(1 << clk->enable_bit); | ||
1067 | else if (rate == 48000000) | ||
1068 | val |= (1 << clk->enable_bit); | ||
1069 | else | ||
1070 | return -EINVAL; | ||
1071 | omap_writel(val, clk->enable_reg); | ||
1072 | clk->rate = rate; | ||
1073 | |||
1074 | return 0; | ||
1075 | } | ||
1076 | |||
1077 | static int set_ext_clk_rate(struct clk * clk, unsigned long rate) | ||
1078 | { | 218 | { |
1079 | unsigned dsor; | 219 | get_option(&str, &mpurate); |
1080 | __u16 ratio_bits; | ||
1081 | 220 | ||
1082 | dsor = calc_ext_dsor(rate); | 221 | if (!mpurate) |
1083 | clk->rate = 96000000 / dsor; | 222 | return 1; |
1084 | if (dsor > 8) | ||
1085 | ratio_bits = ((dsor - 8) / 2 + 6) << 2; | ||
1086 | else | ||
1087 | ratio_bits = (dsor - 2) << 2; | ||
1088 | 223 | ||
1089 | ratio_bits |= omap_readw(clk->enable_reg) & ~0xfd; | 224 | if (mpurate < 1000) |
1090 | omap_writew(ratio_bits, clk->enable_reg); | 225 | mpurate *= 1000000; |
1091 | 226 | ||
1092 | return 0; | 227 | return 1; |
1093 | } | 228 | } |
229 | __setup("mpurate=", omap_clk_setup); | ||
1094 | 230 | ||
1095 | 231 | /* Used for clocks that always have same value as the parent clock */ | |
1096 | static long round_ext_clk_rate(struct clk * clk, unsigned long rate) | 232 | void followparent_recalc(struct clk *clk) |
1097 | { | 233 | { |
1098 | return 96000000 / calc_ext_dsor(rate); | 234 | clk->rate = clk->parent->rate; |
1099 | } | 235 | } |
1100 | 236 | ||
1101 | 237 | /* Propagate rate to children */ | |
1102 | static void init_ext_clk(struct clk * clk) | 238 | void propagate_rate(struct clk * tclk) |
1103 | { | 239 | { |
1104 | unsigned dsor; | 240 | struct clk *clkp; |
1105 | __u16 ratio_bits; | ||
1106 | 241 | ||
1107 | /* Determine current rate and ensure clock is based on 96MHz APLL */ | 242 | list_for_each_entry(clkp, &clocks, node) { |
1108 | ratio_bits = omap_readw(clk->enable_reg) & ~1; | 243 | if (likely(clkp->parent != tclk)) |
1109 | omap_writew(ratio_bits, clk->enable_reg); | 244 | continue; |
1110 | 245 | if (likely((u32)clkp->recalc)) | |
1111 | ratio_bits = (ratio_bits & 0xfc) >> 2; | 246 | clkp->recalc(clkp); |
1112 | if (ratio_bits > 6) | 247 | } |
1113 | dsor = (ratio_bits - 6) * 2 + 8; | ||
1114 | else | ||
1115 | dsor = ratio_bits + 2; | ||
1116 | |||
1117 | clk-> rate = 96000000 / dsor; | ||
1118 | } | 248 | } |
1119 | 249 | ||
1120 | |||
1121 | int clk_register(struct clk *clk) | 250 | int clk_register(struct clk *clk) |
1122 | { | 251 | { |
1123 | down(&clocks_sem); | 252 | down(&clocks_sem); |
@@ -1125,6 +254,7 @@ int clk_register(struct clk *clk) | |||
1125 | if (clk->init) | 254 | if (clk->init) |
1126 | clk->init(clk); | 255 | clk->init(clk); |
1127 | up(&clocks_sem); | 256 | up(&clocks_sem); |
257 | |||
1128 | return 0; | 258 | return 0; |
1129 | } | 259 | } |
1130 | EXPORT_SYMBOL(clk_register); | 260 | EXPORT_SYMBOL(clk_register); |
@@ -1137,203 +267,38 @@ void clk_unregister(struct clk *clk) | |||
1137 | } | 267 | } |
1138 | EXPORT_SYMBOL(clk_unregister); | 268 | EXPORT_SYMBOL(clk_unregister); |
1139 | 269 | ||
1140 | #ifdef CONFIG_OMAP_RESET_CLOCKS | 270 | void clk_deny_idle(struct clk *clk) |
1141 | /* | ||
1142 | * Resets some clocks that may be left on from bootloader, | ||
1143 | * but leaves serial clocks on. See also omap_late_clk_reset(). | ||
1144 | */ | ||
1145 | static inline void omap_early_clk_reset(void) | ||
1146 | { | 271 | { |
1147 | //omap_writel(0x3 << 29, MOD_CONF_CTRL_0); | 272 | unsigned long flags; |
273 | |||
274 | spin_lock_irqsave(&clockfw_lock, flags); | ||
275 | if (arch_clock->clk_deny_idle) | ||
276 | arch_clock->clk_deny_idle(clk); | ||
277 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
1148 | } | 278 | } |
1149 | #else | 279 | EXPORT_SYMBOL(clk_deny_idle); |
1150 | #define omap_early_clk_reset() {} | ||
1151 | #endif | ||
1152 | 280 | ||
1153 | int __init clk_init(void) | 281 | void clk_allow_idle(struct clk *clk) |
1154 | { | 282 | { |
1155 | struct clk ** clkp; | 283 | unsigned long flags; |
1156 | const struct omap_clock_config *info; | ||
1157 | int crystal_type = 0; /* Default 12 MHz */ | ||
1158 | |||
1159 | omap_early_clk_reset(); | ||
1160 | |||
1161 | for (clkp = onchip_clks; clkp < onchip_clks+ARRAY_SIZE(onchip_clks); clkp++) { | ||
1162 | if (((*clkp)->flags &CLOCK_IN_OMAP1510) && cpu_is_omap1510()) { | ||
1163 | clk_register(*clkp); | ||
1164 | continue; | ||
1165 | } | ||
1166 | |||
1167 | if (((*clkp)->flags &CLOCK_IN_OMAP16XX) && cpu_is_omap16xx()) { | ||
1168 | clk_register(*clkp); | ||
1169 | continue; | ||
1170 | } | ||
1171 | |||
1172 | if (((*clkp)->flags &CLOCK_IN_OMAP730) && cpu_is_omap730()) { | ||
1173 | clk_register(*clkp); | ||
1174 | continue; | ||
1175 | } | ||
1176 | } | ||
1177 | |||
1178 | info = omap_get_config(OMAP_TAG_CLOCK, struct omap_clock_config); | ||
1179 | if (info != NULL) { | ||
1180 | if (!cpu_is_omap1510()) | ||
1181 | crystal_type = info->system_clock_type; | ||
1182 | } | ||
1183 | |||
1184 | #if defined(CONFIG_ARCH_OMAP730) | ||
1185 | ck_ref.rate = 13000000; | ||
1186 | #elif defined(CONFIG_ARCH_OMAP16XX) | ||
1187 | if (crystal_type == 2) | ||
1188 | ck_ref.rate = 19200000; | ||
1189 | #endif | ||
1190 | |||
1191 | printk("Clocks: ARM_SYSST: 0x%04x DPLL_CTL: 0x%04x ARM_CKCTL: 0x%04x\n", | ||
1192 | omap_readw(ARM_SYSST), omap_readw(DPLL_CTL), | ||
1193 | omap_readw(ARM_CKCTL)); | ||
1194 | |||
1195 | /* We want to be in syncronous scalable mode */ | ||
1196 | omap_writew(0x1000, ARM_SYSST); | ||
1197 | |||
1198 | #ifdef CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER | ||
1199 | /* Use values set by bootloader. Determine PLL rate and recalculate | ||
1200 | * dependent clocks as if kernel had changed PLL or divisors. | ||
1201 | */ | ||
1202 | { | ||
1203 | unsigned pll_ctl_val = omap_readw(DPLL_CTL); | ||
1204 | |||
1205 | ck_dpll1.rate = ck_ref.rate; /* Base xtal rate */ | ||
1206 | if (pll_ctl_val & 0x10) { | ||
1207 | /* PLL enabled, apply multiplier and divisor */ | ||
1208 | if (pll_ctl_val & 0xf80) | ||
1209 | ck_dpll1.rate *= (pll_ctl_val & 0xf80) >> 7; | ||
1210 | ck_dpll1.rate /= ((pll_ctl_val & 0x60) >> 5) + 1; | ||
1211 | } else { | ||
1212 | /* PLL disabled, apply bypass divisor */ | ||
1213 | switch (pll_ctl_val & 0xc) { | ||
1214 | case 0: | ||
1215 | break; | ||
1216 | case 0x4: | ||
1217 | ck_dpll1.rate /= 2; | ||
1218 | break; | ||
1219 | default: | ||
1220 | ck_dpll1.rate /= 4; | ||
1221 | break; | ||
1222 | } | ||
1223 | } | ||
1224 | } | ||
1225 | propagate_rate(&ck_dpll1); | ||
1226 | #else | ||
1227 | /* Find the highest supported frequency and enable it */ | ||
1228 | if (select_table_rate(&virtual_ck_mpu, ~0)) { | ||
1229 | printk(KERN_ERR "System frequencies not set. Check your config.\n"); | ||
1230 | /* Guess sane values (60MHz) */ | ||
1231 | omap_writew(0x2290, DPLL_CTL); | ||
1232 | omap_writew(0x1005, ARM_CKCTL); | ||
1233 | ck_dpll1.rate = 60000000; | ||
1234 | propagate_rate(&ck_dpll1); | ||
1235 | } | ||
1236 | #endif | ||
1237 | /* Cache rates for clocks connected to ck_ref (not dpll1) */ | ||
1238 | propagate_rate(&ck_ref); | ||
1239 | printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): " | ||
1240 | "%ld.%01ld/%ld.%01ld/%ld.%01ld MHz\n", | ||
1241 | ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10, | ||
1242 | ck_dpll1.rate / 1000000, (ck_dpll1.rate / 100000) % 10, | ||
1243 | arm_ck.rate / 1000000, (arm_ck.rate / 100000) % 10); | ||
1244 | |||
1245 | #ifdef CONFIG_MACH_OMAP_PERSEUS2 | ||
1246 | /* Select slicer output as OMAP input clock */ | ||
1247 | omap_writew(omap_readw(OMAP730_PCC_UPLD_CTRL) & ~0x1, OMAP730_PCC_UPLD_CTRL); | ||
1248 | #endif | ||
1249 | |||
1250 | /* Turn off DSP and ARM_TIMXO. Make sure ARM_INTHCK is not divided */ | ||
1251 | omap_writew(omap_readw(ARM_CKCTL) & 0x0fff, ARM_CKCTL); | ||
1252 | |||
1253 | /* Put DSP/MPUI into reset until needed */ | ||
1254 | omap_writew(0, ARM_RSTCT1); | ||
1255 | omap_writew(1, ARM_RSTCT2); | ||
1256 | omap_writew(0x400, ARM_IDLECT1); | ||
1257 | |||
1258 | /* | ||
1259 | * According to OMAP5910 Erratum SYS_DMA_1, bit DMACK_REQ (bit 8) | ||
1260 | * of the ARM_IDLECT2 register must be set to zero. The power-on | ||
1261 | * default value of this bit is one. | ||
1262 | */ | ||
1263 | omap_writew(0x0000, ARM_IDLECT2); /* Turn LCD clock off also */ | ||
1264 | |||
1265 | /* | ||
1266 | * Only enable those clocks we will need, let the drivers | ||
1267 | * enable other clocks as necessary | ||
1268 | */ | ||
1269 | clk_use(&armper_ck); | ||
1270 | clk_use(&armxor_ck); | ||
1271 | clk_use(&armtim_ck); | ||
1272 | |||
1273 | if (cpu_is_omap1510()) | ||
1274 | clk_enable(&arm_gpio_ck); | ||
1275 | 284 | ||
1276 | return 0; | 285 | spin_lock_irqsave(&clockfw_lock, flags); |
286 | if (arch_clock->clk_allow_idle) | ||
287 | arch_clock->clk_allow_idle(clk); | ||
288 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
1277 | } | 289 | } |
290 | EXPORT_SYMBOL(clk_allow_idle); | ||
1278 | 291 | ||
292 | /*-------------------------------------------------------------------------*/ | ||
1279 | 293 | ||
1280 | #ifdef CONFIG_OMAP_RESET_CLOCKS | 294 | int __init clk_init(struct clk_functions * custom_clocks) |
1281 | |||
1282 | static int __init omap_late_clk_reset(void) | ||
1283 | { | 295 | { |
1284 | /* Turn off all unused clocks */ | 296 | if (!custom_clocks) { |
1285 | struct clk *p; | 297 | printk(KERN_ERR "No custom clock functions registered\n"); |
1286 | __u32 regval32; | 298 | BUG(); |
1287 | |||
1288 | /* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */ | ||
1289 | regval32 = omap_readw(SOFT_REQ_REG) & (1 << 4); | ||
1290 | omap_writew(regval32, SOFT_REQ_REG); | ||
1291 | omap_writew(0, SOFT_REQ_REG2); | ||
1292 | |||
1293 | list_for_each_entry(p, &clocks, node) { | ||
1294 | if (p->usecount > 0 || (p->flags & ALWAYS_ENABLED) || | ||
1295 | p->enable_reg == 0) | ||
1296 | continue; | ||
1297 | |||
1298 | /* Assume no DSP clocks have been activated by bootloader */ | ||
1299 | if (p->flags & DSP_DOMAIN_CLOCK) | ||
1300 | continue; | ||
1301 | |||
1302 | /* Is the clock already disabled? */ | ||
1303 | if (p->flags & ENABLE_REG_32BIT) { | ||
1304 | if (p->flags & VIRTUAL_IO_ADDRESS) | ||
1305 | regval32 = __raw_readl(p->enable_reg); | ||
1306 | else | ||
1307 | regval32 = omap_readl(p->enable_reg); | ||
1308 | } else { | ||
1309 | if (p->flags & VIRTUAL_IO_ADDRESS) | ||
1310 | regval32 = __raw_readw(p->enable_reg); | ||
1311 | else | ||
1312 | regval32 = omap_readw(p->enable_reg); | ||
1313 | } | ||
1314 | |||
1315 | if ((regval32 & (1 << p->enable_bit)) == 0) | ||
1316 | continue; | ||
1317 | |||
1318 | /* FIXME: This clock seems to be necessary but no-one | ||
1319 | * has asked for its activation. */ | ||
1320 | if (p == &tc2_ck // FIX: pm.c (SRAM), CCP, Camera | ||
1321 | || p == &ck_dpll1out // FIX: SoSSI, SSR | ||
1322 | || p == &arm_gpio_ck // FIX: GPIO code for 1510 | ||
1323 | ) { | ||
1324 | printk(KERN_INFO "FIXME: Clock \"%s\" seems unused\n", | ||
1325 | p->name); | ||
1326 | continue; | ||
1327 | } | ||
1328 | |||
1329 | printk(KERN_INFO "Disabling unused clock \"%s\"... ", p->name); | ||
1330 | __clk_disable(p); | ||
1331 | printk(" done\n"); | ||
1332 | } | 299 | } |
1333 | 300 | ||
301 | arch_clock = custom_clocks; | ||
302 | |||
1334 | return 0; | 303 | return 0; |
1335 | } | 304 | } |
1336 | |||
1337 | late_initcall(omap_late_clk_reset); | ||
1338 | |||
1339 | #endif | ||
diff --git a/arch/arm/plat-omap/clock.h b/arch/arm/plat-omap/clock.h deleted file mode 100644 index a89e1e8c2519..000000000000 --- a/arch/arm/plat-omap/clock.h +++ /dev/null | |||
@@ -1,120 +0,0 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/plat-omap/clock.h | ||
3 | * | ||
4 | * Copyright (C) 2004 Nokia corporation | ||
5 | * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> | ||
6 | * Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, Inc | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef __ARCH_ARM_OMAP_CLOCK_H | ||
14 | #define __ARCH_ARM_OMAP_CLOCK_H | ||
15 | |||
16 | struct module; | ||
17 | |||
18 | struct clk { | ||
19 | struct list_head node; | ||
20 | struct module *owner; | ||
21 | const char *name; | ||
22 | struct clk *parent; | ||
23 | unsigned long rate; | ||
24 | __s8 usecount; | ||
25 | __u16 flags; | ||
26 | __u32 enable_reg; | ||
27 | __u8 enable_bit; | ||
28 | __u8 rate_offset; | ||
29 | void (*recalc)(struct clk *); | ||
30 | int (*set_rate)(struct clk *, unsigned long); | ||
31 | long (*round_rate)(struct clk *, unsigned long); | ||
32 | void (*init)(struct clk *); | ||
33 | }; | ||
34 | |||
35 | |||
36 | struct mpu_rate { | ||
37 | unsigned long rate; | ||
38 | unsigned long xtal; | ||
39 | unsigned long pll_rate; | ||
40 | __u16 ckctl_val; | ||
41 | __u16 dpllctl_val; | ||
42 | }; | ||
43 | |||
44 | |||
45 | /* Clock flags */ | ||
46 | #define RATE_CKCTL 1 | ||
47 | #define RATE_FIXED 2 | ||
48 | #define RATE_PROPAGATES 4 | ||
49 | #define VIRTUAL_CLOCK 8 | ||
50 | #define ALWAYS_ENABLED 16 | ||
51 | #define ENABLE_REG_32BIT 32 | ||
52 | #define CLOCK_IN_OMAP16XX 64 | ||
53 | #define CLOCK_IN_OMAP1510 128 | ||
54 | #define CLOCK_IN_OMAP730 256 | ||
55 | #define DSP_DOMAIN_CLOCK 512 | ||
56 | #define VIRTUAL_IO_ADDRESS 1024 | ||
57 | |||
58 | /* ARM_CKCTL bit shifts */ | ||
59 | #define CKCTL_PERDIV_OFFSET 0 | ||
60 | #define CKCTL_LCDDIV_OFFSET 2 | ||
61 | #define CKCTL_ARMDIV_OFFSET 4 | ||
62 | #define CKCTL_DSPDIV_OFFSET 6 | ||
63 | #define CKCTL_TCDIV_OFFSET 8 | ||
64 | #define CKCTL_DSPMMUDIV_OFFSET 10 | ||
65 | /*#define ARM_TIMXO 12*/ | ||
66 | #define EN_DSPCK 13 | ||
67 | /*#define ARM_INTHCK_SEL 14*/ /* Divide-by-2 for mpu inth_ck */ | ||
68 | /* DSP_CKCTL bit shifts */ | ||
69 | #define CKCTL_DSPPERDIV_OFFSET 0 | ||
70 | |||
71 | /* ARM_IDLECT1 bit shifts */ | ||
72 | /*#define IDLWDT_ARM 0*/ | ||
73 | /*#define IDLXORP_ARM 1*/ | ||
74 | /*#define IDLPER_ARM 2*/ | ||
75 | /*#define IDLLCD_ARM 3*/ | ||
76 | /*#define IDLLB_ARM 4*/ | ||
77 | /*#define IDLHSAB_ARM 5*/ | ||
78 | /*#define IDLIF_ARM 6*/ | ||
79 | /*#define IDLDPLL_ARM 7*/ | ||
80 | /*#define IDLAPI_ARM 8*/ | ||
81 | /*#define IDLTIM_ARM 9*/ | ||
82 | /*#define SETARM_IDLE 11*/ | ||
83 | |||
84 | /* ARM_IDLECT2 bit shifts */ | ||
85 | #define EN_WDTCK 0 | ||
86 | #define EN_XORPCK 1 | ||
87 | #define EN_PERCK 2 | ||
88 | #define EN_LCDCK 3 | ||
89 | #define EN_LBCK 4 /* Not on 1610/1710 */ | ||
90 | /*#define EN_HSABCK 5*/ | ||
91 | #define EN_APICK 6 | ||
92 | #define EN_TIMCK 7 | ||
93 | #define DMACK_REQ 8 | ||
94 | #define EN_GPIOCK 9 /* Not on 1610/1710 */ | ||
95 | /*#define EN_LBFREECK 10*/ | ||
96 | #define EN_CKOUT_ARM 11 | ||
97 | |||
98 | /* ARM_IDLECT3 bit shifts */ | ||
99 | #define EN_OCPI_CK 0 | ||
100 | #define EN_TC1_CK 2 | ||
101 | #define EN_TC2_CK 4 | ||
102 | |||
103 | /* DSP_IDLECT2 bit shifts (0,1,2 are same as for ARM_IDLECT2) */ | ||
104 | #define EN_DSPTIMCK 5 | ||
105 | |||
106 | /* Various register defines for clock controls scattered around OMAP chip */ | ||
107 | #define USB_MCLK_EN_BIT 4 /* In ULPD_CLKC_CTRL */ | ||
108 | #define USB_HOST_HHC_UHOST_EN 9 /* In MOD_CONF_CTRL_0 */ | ||
109 | #define SWD_ULPD_PLL_CLK_REQ 1 /* In SWD_CLK_DIV_CTRL_SEL */ | ||
110 | #define COM_ULPD_PLL_CLK_REQ 1 /* In COM_CLK_DIV_CTRL_SEL */ | ||
111 | #define SWD_CLK_DIV_CTRL_SEL 0xfffe0874 | ||
112 | #define COM_CLK_DIV_CTRL_SEL 0xfffe0878 | ||
113 | #define SOFT_REQ_REG 0xfffe0834 | ||
114 | #define SOFT_REQ_REG2 0xfffe0880 | ||
115 | |||
116 | int clk_register(struct clk *clk); | ||
117 | void clk_unregister(struct clk *clk); | ||
118 | int clk_init(void); | ||
119 | |||
120 | #endif | ||
diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c index 02bcc6c1cd1b..ccdb452630cf 100644 --- a/arch/arm/plat-omap/common.c +++ b/arch/arm/plat-omap/common.c | |||
@@ -31,7 +31,7 @@ | |||
31 | #include <asm/arch/mux.h> | 31 | #include <asm/arch/mux.h> |
32 | #include <asm/arch/fpga.h> | 32 | #include <asm/arch/fpga.h> |
33 | 33 | ||
34 | #include "clock.h" | 34 | #include <asm/arch/clock.h> |
35 | 35 | ||
36 | #define NO_LENGTH_CHECK 0xffffffff | 36 | #define NO_LENGTH_CHECK 0xffffffff |
37 | 37 | ||
@@ -117,19 +117,43 @@ EXPORT_SYMBOL(omap_get_var_config); | |||
117 | 117 | ||
118 | static int __init omap_add_serial_console(void) | 118 | static int __init omap_add_serial_console(void) |
119 | { | 119 | { |
120 | const struct omap_serial_console_config *info; | 120 | const struct omap_serial_console_config *con_info; |
121 | 121 | const struct omap_uart_config *uart_info; | |
122 | info = omap_get_config(OMAP_TAG_SERIAL_CONSOLE, | 122 | static char speed[11], *opt = NULL; |
123 | struct omap_serial_console_config); | 123 | int line, i, uart_idx; |
124 | if (info != NULL && info->console_uart) { | 124 | |
125 | static char speed[11], *opt = NULL; | 125 | uart_info = omap_get_config(OMAP_TAG_UART, struct omap_uart_config); |
126 | con_info = omap_get_config(OMAP_TAG_SERIAL_CONSOLE, | ||
127 | struct omap_serial_console_config); | ||
128 | if (uart_info == NULL || con_info == NULL) | ||
129 | return 0; | ||
130 | |||
131 | if (con_info->console_uart == 0) | ||
132 | return 0; | ||
133 | |||
134 | if (con_info->console_speed) { | ||
135 | snprintf(speed, sizeof(speed), "%u", con_info->console_speed); | ||
136 | opt = speed; | ||
137 | } | ||
126 | 138 | ||
127 | if (info->console_speed) { | 139 | uart_idx = con_info->console_uart - 1; |
128 | snprintf(speed, sizeof(speed), "%u", info->console_speed); | 140 | if (uart_idx >= OMAP_MAX_NR_PORTS) { |
129 | opt = speed; | 141 | printk(KERN_INFO "Console: external UART#%d. " |
130 | } | 142 | "Not adding it as console this time.\n", |
131 | return add_preferred_console("ttyS", info->console_uart - 1, opt); | 143 | uart_idx + 1); |
144 | return 0; | ||
145 | } | ||
146 | if (!(uart_info->enabled_uarts & (1 << uart_idx))) { | ||
147 | printk(KERN_ERR "Console: Selected UART#%d is " | ||
148 | "not enabled for this platform\n", | ||
149 | uart_idx + 1); | ||
150 | return -1; | ||
151 | } | ||
152 | line = 0; | ||
153 | for (i = 0; i < uart_idx; i++) { | ||
154 | if (uart_info->enabled_uarts & (1 << i)) | ||
155 | line++; | ||
132 | } | 156 | } |
133 | return 0; | 157 | return add_preferred_console("ttyS", line, opt); |
134 | } | 158 | } |
135 | console_initcall(omap_add_serial_console); | 159 | console_initcall(omap_add_serial_console); |
diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c new file mode 100644 index 000000000000..9dcce904b608 --- /dev/null +++ b/arch/arm/plat-omap/devices.c | |||
@@ -0,0 +1,381 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/plat-omap/devices.c | ||
3 | * | ||
4 | * Common platform device setup/initialization for OMAP1 and OMAP2 | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | |||
18 | #include <asm/hardware.h> | ||
19 | #include <asm/io.h> | ||
20 | #include <asm/mach-types.h> | ||
21 | #include <asm/mach/map.h> | ||
22 | |||
23 | #include <asm/arch/tc.h> | ||
24 | #include <asm/arch/board.h> | ||
25 | #include <asm/arch/mux.h> | ||
26 | #include <asm/arch/gpio.h> | ||
27 | |||
28 | |||
29 | void omap_nop_release(struct device *dev) | ||
30 | { | ||
31 | /* Nothing */ | ||
32 | } | ||
33 | |||
34 | /*-------------------------------------------------------------------------*/ | ||
35 | |||
36 | #if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE) | ||
37 | |||
38 | #define OMAP1_I2C_BASE 0xfffb3800 | ||
39 | #define OMAP2_I2C_BASE1 0x48070000 | ||
40 | #define OMAP_I2C_SIZE 0x3f | ||
41 | #define OMAP1_I2C_INT INT_I2C | ||
42 | #define OMAP2_I2C_INT1 56 | ||
43 | |||
44 | static struct resource i2c_resources1[] = { | ||
45 | { | ||
46 | .start = 0, | ||
47 | .end = 0, | ||
48 | .flags = IORESOURCE_MEM, | ||
49 | }, | ||
50 | { | ||
51 | .start = 0, | ||
52 | .flags = IORESOURCE_IRQ, | ||
53 | }, | ||
54 | }; | ||
55 | |||
56 | /* DMA not used; works around erratum writing to non-empty i2c fifo */ | ||
57 | |||
58 | static struct platform_device omap_i2c_device1 = { | ||
59 | .name = "i2c_omap", | ||
60 | .id = 1, | ||
61 | .dev = { | ||
62 | .release = omap_nop_release, | ||
63 | }, | ||
64 | .num_resources = ARRAY_SIZE(i2c_resources1), | ||
65 | .resource = i2c_resources1, | ||
66 | }; | ||
67 | |||
68 | /* See also arch/arm/mach-omap2/devices.c for second I2C on 24xx */ | ||
69 | static void omap_init_i2c(void) | ||
70 | { | ||
71 | if (cpu_is_omap24xx()) { | ||
72 | i2c_resources1[0].start = OMAP2_I2C_BASE1; | ||
73 | i2c_resources1[0].end = OMAP2_I2C_BASE1 + OMAP_I2C_SIZE; | ||
74 | i2c_resources1[1].start = OMAP2_I2C_INT1; | ||
75 | } else { | ||
76 | i2c_resources1[0].start = OMAP1_I2C_BASE; | ||
77 | i2c_resources1[0].end = OMAP1_I2C_BASE + OMAP_I2C_SIZE; | ||
78 | i2c_resources1[1].start = OMAP1_I2C_INT; | ||
79 | } | ||
80 | |||
81 | /* FIXME define and use a boot tag, in case of boards that | ||
82 | * either don't wire up I2C, or chips that mux it differently... | ||
83 | * it can include clocking and address info, maybe more. | ||
84 | */ | ||
85 | if (cpu_is_omap24xx()) { | ||
86 | omap_cfg_reg(M19_24XX_I2C1_SCL); | ||
87 | omap_cfg_reg(L15_24XX_I2C1_SDA); | ||
88 | } else { | ||
89 | omap_cfg_reg(I2C_SCL); | ||
90 | omap_cfg_reg(I2C_SDA); | ||
91 | } | ||
92 | |||
93 | (void) platform_device_register(&omap_i2c_device1); | ||
94 | } | ||
95 | |||
96 | #else | ||
97 | static inline void omap_init_i2c(void) {} | ||
98 | #endif | ||
99 | |||
100 | /*-------------------------------------------------------------------------*/ | ||
101 | |||
102 | #if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) | ||
103 | |||
104 | #ifdef CONFIG_ARCH_OMAP24XX | ||
105 | #define OMAP_MMC1_BASE 0x4809c000 | ||
106 | #define OMAP_MMC1_INT 83 | ||
107 | #else | ||
108 | #define OMAP_MMC1_BASE 0xfffb7800 | ||
109 | #define OMAP_MMC1_INT INT_MMC | ||
110 | #endif | ||
111 | #define OMAP_MMC2_BASE 0xfffb7c00 /* omap16xx only */ | ||
112 | |||
113 | static struct omap_mmc_conf mmc1_conf; | ||
114 | |||
115 | static u64 mmc1_dmamask = 0xffffffff; | ||
116 | |||
117 | static struct resource mmc1_resources[] = { | ||
118 | { | ||
119 | .start = IO_ADDRESS(OMAP_MMC1_BASE), | ||
120 | .end = IO_ADDRESS(OMAP_MMC1_BASE) + 0x7f, | ||
121 | .flags = IORESOURCE_MEM, | ||
122 | }, | ||
123 | { | ||
124 | .start = OMAP_MMC1_INT, | ||
125 | .flags = IORESOURCE_IRQ, | ||
126 | }, | ||
127 | }; | ||
128 | |||
129 | static struct platform_device mmc_omap_device1 = { | ||
130 | .name = "mmci-omap", | ||
131 | .id = 1, | ||
132 | .dev = { | ||
133 | .release = omap_nop_release, | ||
134 | .dma_mask = &mmc1_dmamask, | ||
135 | .platform_data = &mmc1_conf, | ||
136 | }, | ||
137 | .num_resources = ARRAY_SIZE(mmc1_resources), | ||
138 | .resource = mmc1_resources, | ||
139 | }; | ||
140 | |||
141 | #ifdef CONFIG_ARCH_OMAP16XX | ||
142 | |||
143 | static struct omap_mmc_conf mmc2_conf; | ||
144 | |||
145 | static u64 mmc2_dmamask = 0xffffffff; | ||
146 | |||
147 | static struct resource mmc2_resources[] = { | ||
148 | { | ||
149 | .start = IO_ADDRESS(OMAP_MMC2_BASE), | ||
150 | .end = IO_ADDRESS(OMAP_MMC2_BASE) + 0x7f, | ||
151 | .flags = IORESOURCE_MEM, | ||
152 | }, | ||
153 | { | ||
154 | .start = INT_1610_MMC2, | ||
155 | .flags = IORESOURCE_IRQ, | ||
156 | }, | ||
157 | }; | ||
158 | |||
159 | static struct platform_device mmc_omap_device2 = { | ||
160 | .name = "mmci-omap", | ||
161 | .id = 2, | ||
162 | .dev = { | ||
163 | .release = omap_nop_release, | ||
164 | .dma_mask = &mmc2_dmamask, | ||
165 | .platform_data = &mmc2_conf, | ||
166 | }, | ||
167 | .num_resources = ARRAY_SIZE(mmc2_resources), | ||
168 | .resource = mmc2_resources, | ||
169 | }; | ||
170 | #endif | ||
171 | |||
172 | static void __init omap_init_mmc(void) | ||
173 | { | ||
174 | const struct omap_mmc_config *mmc_conf; | ||
175 | const struct omap_mmc_conf *mmc; | ||
176 | |||
177 | /* NOTE: assumes MMC was never (wrongly) enabled */ | ||
178 | mmc_conf = omap_get_config(OMAP_TAG_MMC, struct omap_mmc_config); | ||
179 | if (!mmc_conf) | ||
180 | return; | ||
181 | |||
182 | /* block 1 is always available and has just one pinout option */ | ||
183 | mmc = &mmc_conf->mmc[0]; | ||
184 | if (mmc->enabled) { | ||
185 | if (!cpu_is_omap24xx()) { | ||
186 | omap_cfg_reg(MMC_CMD); | ||
187 | omap_cfg_reg(MMC_CLK); | ||
188 | omap_cfg_reg(MMC_DAT0); | ||
189 | if (cpu_is_omap1710()) { | ||
190 | omap_cfg_reg(M15_1710_MMC_CLKI); | ||
191 | omap_cfg_reg(P19_1710_MMC_CMDDIR); | ||
192 | omap_cfg_reg(P20_1710_MMC_DATDIR0); | ||
193 | } | ||
194 | } | ||
195 | if (mmc->wire4) { | ||
196 | if (!cpu_is_omap24xx()) { | ||
197 | omap_cfg_reg(MMC_DAT1); | ||
198 | /* NOTE: DAT2 can be on W10 (here) or M15 */ | ||
199 | if (!mmc->nomux) | ||
200 | omap_cfg_reg(MMC_DAT2); | ||
201 | omap_cfg_reg(MMC_DAT3); | ||
202 | } | ||
203 | } | ||
204 | mmc1_conf = *mmc; | ||
205 | (void) platform_device_register(&mmc_omap_device1); | ||
206 | } | ||
207 | |||
208 | #ifdef CONFIG_ARCH_OMAP16XX | ||
209 | /* block 2 is on newer chips, and has many pinout options */ | ||
210 | mmc = &mmc_conf->mmc[1]; | ||
211 | if (mmc->enabled) { | ||
212 | if (!mmc->nomux) { | ||
213 | omap_cfg_reg(Y8_1610_MMC2_CMD); | ||
214 | omap_cfg_reg(Y10_1610_MMC2_CLK); | ||
215 | omap_cfg_reg(R18_1610_MMC2_CLKIN); | ||
216 | omap_cfg_reg(W8_1610_MMC2_DAT0); | ||
217 | if (mmc->wire4) { | ||
218 | omap_cfg_reg(V8_1610_MMC2_DAT1); | ||
219 | omap_cfg_reg(W15_1610_MMC2_DAT2); | ||
220 | omap_cfg_reg(R10_1610_MMC2_DAT3); | ||
221 | } | ||
222 | |||
223 | /* These are needed for the level shifter */ | ||
224 | omap_cfg_reg(V9_1610_MMC2_CMDDIR); | ||
225 | omap_cfg_reg(V5_1610_MMC2_DATDIR0); | ||
226 | omap_cfg_reg(W19_1610_MMC2_DATDIR1); | ||
227 | } | ||
228 | |||
229 | /* Feedback clock must be set on OMAP-1710 MMC2 */ | ||
230 | if (cpu_is_omap1710()) | ||
231 | omap_writel(omap_readl(MOD_CONF_CTRL_1) | (1 << 24), | ||
232 | MOD_CONF_CTRL_1); | ||
233 | mmc2_conf = *mmc; | ||
234 | (void) platform_device_register(&mmc_omap_device2); | ||
235 | } | ||
236 | #endif | ||
237 | return; | ||
238 | } | ||
239 | #else | ||
240 | static inline void omap_init_mmc(void) {} | ||
241 | #endif | ||
242 | |||
243 | #if defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE) | ||
244 | |||
245 | #ifdef CONFIG_ARCH_OMAP24XX | ||
246 | #define OMAP_WDT_BASE 0x48022000 | ||
247 | #else | ||
248 | #define OMAP_WDT_BASE 0xfffeb000 | ||
249 | #endif | ||
250 | |||
251 | static struct resource wdt_resources[] = { | ||
252 | { | ||
253 | .start = OMAP_WDT_BASE, | ||
254 | .end = OMAP_WDT_BASE + 0x4f, | ||
255 | .flags = IORESOURCE_MEM, | ||
256 | }, | ||
257 | }; | ||
258 | |||
259 | static struct platform_device omap_wdt_device = { | ||
260 | .name = "omap_wdt", | ||
261 | .id = -1, | ||
262 | .dev = { | ||
263 | .release = omap_nop_release, | ||
264 | }, | ||
265 | .num_resources = ARRAY_SIZE(wdt_resources), | ||
266 | .resource = wdt_resources, | ||
267 | }; | ||
268 | |||
269 | static void omap_init_wdt(void) | ||
270 | { | ||
271 | (void) platform_device_register(&omap_wdt_device); | ||
272 | } | ||
273 | #else | ||
274 | static inline void omap_init_wdt(void) {} | ||
275 | #endif | ||
276 | |||
277 | /*-------------------------------------------------------------------------*/ | ||
278 | |||
279 | #if defined(CONFIG_OMAP_RNG) || defined(CONFIG_OMAP_RNG_MODULE) | ||
280 | |||
281 | #ifdef CONFIG_ARCH_OMAP24XX | ||
282 | #define OMAP_RNG_BASE 0x480A0000 | ||
283 | #else | ||
284 | #define OMAP_RNG_BASE 0xfffe5000 | ||
285 | #endif | ||
286 | |||
287 | static struct resource rng_resources[] = { | ||
288 | { | ||
289 | .start = OMAP_RNG_BASE, | ||
290 | .end = OMAP_RNG_BASE + 0x4f, | ||
291 | .flags = IORESOURCE_MEM, | ||
292 | }, | ||
293 | }; | ||
294 | |||
295 | static struct platform_device omap_rng_device = { | ||
296 | .name = "omap_rng", | ||
297 | .id = -1, | ||
298 | .dev = { | ||
299 | .release = omap_nop_release, | ||
300 | }, | ||
301 | .num_resources = ARRAY_SIZE(rng_resources), | ||
302 | .resource = rng_resources, | ||
303 | }; | ||
304 | |||
305 | static void omap_init_rng(void) | ||
306 | { | ||
307 | (void) platform_device_register(&omap_rng_device); | ||
308 | } | ||
309 | #else | ||
310 | static inline void omap_init_rng(void) {} | ||
311 | #endif | ||
312 | |||
313 | #if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE) | ||
314 | |||
315 | static struct omap_lcd_config omap_fb_conf; | ||
316 | |||
317 | static u64 omap_fb_dma_mask = ~(u32)0; | ||
318 | |||
319 | static struct platform_device omap_fb_device = { | ||
320 | .name = "omapfb", | ||
321 | .id = -1, | ||
322 | .dev = { | ||
323 | .release = omap_nop_release, | ||
324 | .dma_mask = &omap_fb_dma_mask, | ||
325 | .coherent_dma_mask = ~(u32)0, | ||
326 | .platform_data = &omap_fb_conf, | ||
327 | }, | ||
328 | .num_resources = 0, | ||
329 | }; | ||
330 | |||
331 | static inline void omap_init_fb(void) | ||
332 | { | ||
333 | const struct omap_lcd_config *conf; | ||
334 | |||
335 | conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config); | ||
336 | if (conf != NULL) | ||
337 | omap_fb_conf = *conf; | ||
338 | platform_device_register(&omap_fb_device); | ||
339 | } | ||
340 | |||
341 | #else | ||
342 | |||
343 | static inline void omap_init_fb(void) {} | ||
344 | |||
345 | #endif | ||
346 | |||
347 | /* | ||
348 | * This gets called after board-specific INIT_MACHINE, and initializes most | ||
349 | * on-chip peripherals accessible on this board (except for few like USB): | ||
350 | * | ||
351 | * (a) Does any "standard config" pin muxing needed. Board-specific | ||
352 | * code will have muxed GPIO pins and done "nonstandard" setup; | ||
353 | * that code could live in the boot loader. | ||
354 | * (b) Populating board-specific platform_data with the data drivers | ||
355 | * rely on to handle wiring variations. | ||
356 | * (c) Creating platform devices as meaningful on this board and | ||
357 | * with this kernel configuration. | ||
358 | * | ||
359 | * Claiming GPIOs, and setting their direction and initial values, is the | ||
360 | * responsibility of the device drivers. So is responding to probe(). | ||
361 | * | ||
362 | * Board-specific knowlege like creating devices or pin setup is to be | ||
363 | * kept out of drivers as much as possible. In particular, pin setup | ||
364 | * may be handled by the boot loader, and drivers should expect it will | ||
365 | * normally have been done by the time they're probed. | ||
366 | */ | ||
367 | static int __init omap_init_devices(void) | ||
368 | { | ||
369 | /* please keep these calls, and their implementations above, | ||
370 | * in alphabetical order so they're easier to sort through. | ||
371 | */ | ||
372 | omap_init_fb(); | ||
373 | omap_init_i2c(); | ||
374 | omap_init_mmc(); | ||
375 | omap_init_wdt(); | ||
376 | omap_init_rng(); | ||
377 | |||
378 | return 0; | ||
379 | } | ||
380 | arch_initcall(omap_init_devices); | ||
381 | |||
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c index da7b65145658..f5cc21ad0956 100644 --- a/arch/arm/plat-omap/dma.c +++ b/arch/arm/plat-omap/dma.c | |||
@@ -6,6 +6,8 @@ | |||
6 | * DMA channel linking for 1610 by Samuel Ortiz <samuel.ortiz@nokia.com> | 6 | * DMA channel linking for 1610 by Samuel Ortiz <samuel.ortiz@nokia.com> |
7 | * Graphics DMA and LCD DMA graphics tranformations | 7 | * Graphics DMA and LCD DMA graphics tranformations |
8 | * by Imre Deak <imre.deak@nokia.com> | 8 | * by Imre Deak <imre.deak@nokia.com> |
9 | * OMAP2 support Copyright (C) 2004-2005 Texas Instruments, Inc. | ||
10 | * Merged to support both OMAP1 and OMAP2 by Tony Lindgren <tony@atomide.com> | ||
9 | * Some functions based on earlier dma-omap.c Copyright (C) 2001 RidgeRun, Inc. | 11 | * Some functions based on earlier dma-omap.c Copyright (C) 2001 RidgeRun, Inc. |
10 | * | 12 | * |
11 | * Support functions for the OMAP internal DMA channels. | 13 | * Support functions for the OMAP internal DMA channels. |
@@ -31,8 +33,15 @@ | |||
31 | 33 | ||
32 | #include <asm/arch/tc.h> | 34 | #include <asm/arch/tc.h> |
33 | 35 | ||
34 | #define OMAP_DMA_ACTIVE 0x01 | 36 | #define DEBUG_PRINTS |
37 | #undef DEBUG_PRINTS | ||
38 | #ifdef DEBUG_PRINTS | ||
39 | #define debug_printk(x) printk x | ||
40 | #else | ||
41 | #define debug_printk(x) | ||
42 | #endif | ||
35 | 43 | ||
44 | #define OMAP_DMA_ACTIVE 0x01 | ||
36 | #define OMAP_DMA_CCR_EN (1 << 7) | 45 | #define OMAP_DMA_CCR_EN (1 << 7) |
37 | 46 | ||
38 | #define OMAP_FUNC_MUX_ARM_BASE (0xfffe1000 + 0xec) | 47 | #define OMAP_FUNC_MUX_ARM_BASE (0xfffe1000 + 0xec) |
@@ -55,7 +64,7 @@ static int dma_chan_count; | |||
55 | static spinlock_t dma_chan_lock; | 64 | static spinlock_t dma_chan_lock; |
56 | static struct omap_dma_lch dma_chan[OMAP_LOGICAL_DMA_CH_COUNT]; | 65 | static struct omap_dma_lch dma_chan[OMAP_LOGICAL_DMA_CH_COUNT]; |
57 | 66 | ||
58 | const static u8 dma_irq[OMAP_LOGICAL_DMA_CH_COUNT] = { | 67 | const static u8 omap1_dma_irq[OMAP_LOGICAL_DMA_CH_COUNT] = { |
59 | INT_DMA_CH0_6, INT_DMA_CH1_7, INT_DMA_CH2_8, INT_DMA_CH3, | 68 | INT_DMA_CH0_6, INT_DMA_CH1_7, INT_DMA_CH2_8, INT_DMA_CH3, |
60 | INT_DMA_CH4, INT_DMA_CH5, INT_1610_DMA_CH6, INT_1610_DMA_CH7, | 69 | INT_DMA_CH4, INT_DMA_CH5, INT_1610_DMA_CH6, INT_1610_DMA_CH7, |
61 | INT_1610_DMA_CH8, INT_1610_DMA_CH9, INT_1610_DMA_CH10, | 70 | INT_1610_DMA_CH8, INT_1610_DMA_CH9, INT_1610_DMA_CH10, |
@@ -63,6 +72,20 @@ const static u8 dma_irq[OMAP_LOGICAL_DMA_CH_COUNT] = { | |||
63 | INT_1610_DMA_CH14, INT_1610_DMA_CH15, INT_DMA_LCD | 72 | INT_1610_DMA_CH14, INT_1610_DMA_CH15, INT_DMA_LCD |
64 | }; | 73 | }; |
65 | 74 | ||
75 | #define REVISIT_24XX() printk(KERN_ERR "FIXME: no %s on 24xx\n", \ | ||
76 | __FUNCTION__); | ||
77 | |||
78 | #ifdef CONFIG_ARCH_OMAP15XX | ||
79 | /* Returns 1 if the DMA module is in OMAP1510-compatible mode, 0 otherwise */ | ||
80 | int omap_dma_in_1510_mode(void) | ||
81 | { | ||
82 | return enable_1510_mode; | ||
83 | } | ||
84 | #else | ||
85 | #define omap_dma_in_1510_mode() 0 | ||
86 | #endif | ||
87 | |||
88 | #ifdef CONFIG_ARCH_OMAP1 | ||
66 | static inline int get_gdma_dev(int req) | 89 | static inline int get_gdma_dev(int req) |
67 | { | 90 | { |
68 | u32 reg = OMAP_FUNC_MUX_ARM_BASE + ((req - 1) / 5) * 4; | 91 | u32 reg = OMAP_FUNC_MUX_ARM_BASE + ((req - 1) / 5) * 4; |
@@ -82,6 +105,9 @@ static inline void set_gdma_dev(int req, int dev) | |||
82 | l |= (dev - 1) << shift; | 105 | l |= (dev - 1) << shift; |
83 | omap_writel(l, reg); | 106 | omap_writel(l, reg); |
84 | } | 107 | } |
108 | #else | ||
109 | #define set_gdma_dev(req, dev) do {} while (0) | ||
110 | #endif | ||
85 | 111 | ||
86 | static void clear_lch_regs(int lch) | 112 | static void clear_lch_regs(int lch) |
87 | { | 113 | { |
@@ -121,38 +147,62 @@ void omap_set_dma_priority(int dst_port, int priority) | |||
121 | } | 147 | } |
122 | 148 | ||
123 | void omap_set_dma_transfer_params(int lch, int data_type, int elem_count, | 149 | void omap_set_dma_transfer_params(int lch, int data_type, int elem_count, |
124 | int frame_count, int sync_mode) | 150 | int frame_count, int sync_mode, |
151 | int dma_trigger, int src_or_dst_synch) | ||
125 | { | 152 | { |
126 | u16 w; | 153 | OMAP_DMA_CSDP_REG(lch) &= ~0x03; |
154 | OMAP_DMA_CSDP_REG(lch) |= data_type; | ||
127 | 155 | ||
128 | w = omap_readw(OMAP_DMA_CSDP(lch)); | 156 | if (cpu_class_is_omap1()) { |
129 | w &= ~0x03; | 157 | OMAP_DMA_CCR_REG(lch) &= ~(1 << 5); |
130 | w |= data_type; | 158 | if (sync_mode == OMAP_DMA_SYNC_FRAME) |
131 | omap_writew(w, OMAP_DMA_CSDP(lch)); | 159 | OMAP_DMA_CCR_REG(lch) |= 1 << 5; |
160 | |||
161 | OMAP1_DMA_CCR2_REG(lch) &= ~(1 << 2); | ||
162 | if (sync_mode == OMAP_DMA_SYNC_BLOCK) | ||
163 | OMAP1_DMA_CCR2_REG(lch) |= 1 << 2; | ||
164 | } | ||
165 | |||
166 | if (cpu_is_omap24xx() && dma_trigger) { | ||
167 | u32 val = OMAP_DMA_CCR_REG(lch); | ||
168 | |||
169 | if (dma_trigger > 63) | ||
170 | val |= 1 << 20; | ||
171 | if (dma_trigger > 31) | ||
172 | val |= 1 << 19; | ||
132 | 173 | ||
133 | w = omap_readw(OMAP_DMA_CCR(lch)); | 174 | val |= (dma_trigger & 0x1f); |
134 | w &= ~(1 << 5); | ||
135 | if (sync_mode == OMAP_DMA_SYNC_FRAME) | ||
136 | w |= 1 << 5; | ||
137 | omap_writew(w, OMAP_DMA_CCR(lch)); | ||
138 | 175 | ||
139 | w = omap_readw(OMAP_DMA_CCR2(lch)); | 176 | if (sync_mode & OMAP_DMA_SYNC_FRAME) |
140 | w &= ~(1 << 2); | 177 | val |= 1 << 5; |
141 | if (sync_mode == OMAP_DMA_SYNC_BLOCK) | ||
142 | w |= 1 << 2; | ||
143 | omap_writew(w, OMAP_DMA_CCR2(lch)); | ||
144 | 178 | ||
145 | omap_writew(elem_count, OMAP_DMA_CEN(lch)); | 179 | if (sync_mode & OMAP_DMA_SYNC_BLOCK) |
146 | omap_writew(frame_count, OMAP_DMA_CFN(lch)); | 180 | val |= 1 << 18; |
147 | 181 | ||
182 | if (src_or_dst_synch) | ||
183 | val |= 1 << 24; /* source synch */ | ||
184 | else | ||
185 | val &= ~(1 << 24); /* dest synch */ | ||
186 | |||
187 | OMAP_DMA_CCR_REG(lch) = val; | ||
188 | } | ||
189 | |||
190 | OMAP_DMA_CEN_REG(lch) = elem_count; | ||
191 | OMAP_DMA_CFN_REG(lch) = frame_count; | ||
148 | } | 192 | } |
193 | |||
149 | void omap_set_dma_color_mode(int lch, enum omap_dma_color_mode mode, u32 color) | 194 | void omap_set_dma_color_mode(int lch, enum omap_dma_color_mode mode, u32 color) |
150 | { | 195 | { |
151 | u16 w; | 196 | u16 w; |
152 | 197 | ||
153 | BUG_ON(omap_dma_in_1510_mode()); | 198 | BUG_ON(omap_dma_in_1510_mode()); |
154 | 199 | ||
155 | w = omap_readw(OMAP_DMA_CCR2(lch)) & ~0x03; | 200 | if (cpu_is_omap24xx()) { |
201 | REVISIT_24XX(); | ||
202 | return; | ||
203 | } | ||
204 | |||
205 | w = OMAP1_DMA_CCR2_REG(lch) & ~0x03; | ||
156 | switch (mode) { | 206 | switch (mode) { |
157 | case OMAP_DMA_CONSTANT_FILL: | 207 | case OMAP_DMA_CONSTANT_FILL: |
158 | w |= 0x01; | 208 | w |= 0x01; |
@@ -165,63 +215,84 @@ void omap_set_dma_color_mode(int lch, enum omap_dma_color_mode mode, u32 color) | |||
165 | default: | 215 | default: |
166 | BUG(); | 216 | BUG(); |
167 | } | 217 | } |
168 | omap_writew(w, OMAP_DMA_CCR2(lch)); | 218 | OMAP1_DMA_CCR2_REG(lch) = w; |
169 | 219 | ||
170 | w = omap_readw(OMAP_DMA_LCH_CTRL(lch)) & ~0x0f; | 220 | w = OMAP1_DMA_LCH_CTRL_REG(lch) & ~0x0f; |
171 | /* Default is channel type 2D */ | 221 | /* Default is channel type 2D */ |
172 | if (mode) { | 222 | if (mode) { |
173 | omap_writew((u16)color, OMAP_DMA_COLOR_L(lch)); | 223 | OMAP1_DMA_COLOR_L_REG(lch) = (u16)color; |
174 | omap_writew((u16)(color >> 16), OMAP_DMA_COLOR_U(lch)); | 224 | OMAP1_DMA_COLOR_U_REG(lch) = (u16)(color >> 16); |
175 | w |= 1; /* Channel type G */ | 225 | w |= 1; /* Channel type G */ |
176 | } | 226 | } |
177 | omap_writew(w, OMAP_DMA_LCH_CTRL(lch)); | 227 | OMAP1_DMA_LCH_CTRL_REG(lch) = w; |
178 | } | 228 | } |
179 | 229 | ||
180 | 230 | /* Note that src_port is only for omap1 */ | |
181 | void omap_set_dma_src_params(int lch, int src_port, int src_amode, | 231 | void omap_set_dma_src_params(int lch, int src_port, int src_amode, |
182 | unsigned long src_start) | 232 | unsigned long src_start, |
233 | int src_ei, int src_fi) | ||
183 | { | 234 | { |
184 | u16 w; | 235 | if (cpu_class_is_omap1()) { |
236 | OMAP_DMA_CSDP_REG(lch) &= ~(0x1f << 2); | ||
237 | OMAP_DMA_CSDP_REG(lch) |= src_port << 2; | ||
238 | } | ||
239 | |||
240 | OMAP_DMA_CCR_REG(lch) &= ~(0x03 << 12); | ||
241 | OMAP_DMA_CCR_REG(lch) |= src_amode << 12; | ||
242 | |||
243 | if (cpu_class_is_omap1()) { | ||
244 | OMAP1_DMA_CSSA_U_REG(lch) = src_start >> 16; | ||
245 | OMAP1_DMA_CSSA_L_REG(lch) = src_start; | ||
246 | } | ||
185 | 247 | ||
186 | w = omap_readw(OMAP_DMA_CSDP(lch)); | 248 | if (cpu_is_omap24xx()) |
187 | w &= ~(0x1f << 2); | 249 | OMAP2_DMA_CSSA_REG(lch) = src_start; |
188 | w |= src_port << 2; | ||
189 | omap_writew(w, OMAP_DMA_CSDP(lch)); | ||
190 | 250 | ||
191 | w = omap_readw(OMAP_DMA_CCR(lch)); | 251 | OMAP_DMA_CSEI_REG(lch) = src_ei; |
192 | w &= ~(0x03 << 12); | 252 | OMAP_DMA_CSFI_REG(lch) = src_fi; |
193 | w |= src_amode << 12; | 253 | } |
194 | omap_writew(w, OMAP_DMA_CCR(lch)); | ||
195 | 254 | ||
196 | omap_writew(src_start >> 16, OMAP_DMA_CSSA_U(lch)); | 255 | void omap_set_dma_params(int lch, struct omap_dma_channel_params * params) |
197 | omap_writew(src_start, OMAP_DMA_CSSA_L(lch)); | 256 | { |
257 | omap_set_dma_transfer_params(lch, params->data_type, | ||
258 | params->elem_count, params->frame_count, | ||
259 | params->sync_mode, params->trigger, | ||
260 | params->src_or_dst_synch); | ||
261 | omap_set_dma_src_params(lch, params->src_port, | ||
262 | params->src_amode, params->src_start, | ||
263 | params->src_ei, params->src_fi); | ||
264 | |||
265 | omap_set_dma_dest_params(lch, params->dst_port, | ||
266 | params->dst_amode, params->dst_start, | ||
267 | params->dst_ei, params->dst_fi); | ||
198 | } | 268 | } |
199 | 269 | ||
200 | void omap_set_dma_src_index(int lch, int eidx, int fidx) | 270 | void omap_set_dma_src_index(int lch, int eidx, int fidx) |
201 | { | 271 | { |
202 | omap_writew(eidx, OMAP_DMA_CSEI(lch)); | 272 | if (cpu_is_omap24xx()) { |
203 | omap_writew(fidx, OMAP_DMA_CSFI(lch)); | 273 | REVISIT_24XX(); |
274 | return; | ||
275 | } | ||
276 | OMAP_DMA_CSEI_REG(lch) = eidx; | ||
277 | OMAP_DMA_CSFI_REG(lch) = fidx; | ||
204 | } | 278 | } |
205 | 279 | ||
206 | void omap_set_dma_src_data_pack(int lch, int enable) | 280 | void omap_set_dma_src_data_pack(int lch, int enable) |
207 | { | 281 | { |
208 | u16 w; | 282 | OMAP_DMA_CSDP_REG(lch) &= ~(1 << 6); |
209 | 283 | if (enable) | |
210 | w = omap_readw(OMAP_DMA_CSDP(lch)) & ~(1 << 6); | 284 | OMAP_DMA_CSDP_REG(lch) |= (1 << 6); |
211 | w |= enable ? (1 << 6) : 0; | ||
212 | omap_writew(w, OMAP_DMA_CSDP(lch)); | ||
213 | } | 285 | } |
214 | 286 | ||
215 | void omap_set_dma_src_burst_mode(int lch, enum omap_dma_burst_mode burst_mode) | 287 | void omap_set_dma_src_burst_mode(int lch, enum omap_dma_burst_mode burst_mode) |
216 | { | 288 | { |
217 | u16 w; | 289 | OMAP_DMA_CSDP_REG(lch) &= ~(0x03 << 7); |
218 | 290 | ||
219 | w = omap_readw(OMAP_DMA_CSDP(lch)) & ~(0x03 << 7); | ||
220 | switch (burst_mode) { | 291 | switch (burst_mode) { |
221 | case OMAP_DMA_DATA_BURST_DIS: | 292 | case OMAP_DMA_DATA_BURST_DIS: |
222 | break; | 293 | break; |
223 | case OMAP_DMA_DATA_BURST_4: | 294 | case OMAP_DMA_DATA_BURST_4: |
224 | w |= (0x01 << 7); | 295 | OMAP_DMA_CSDP_REG(lch) |= (0x02 << 7); |
225 | break; | 296 | break; |
226 | case OMAP_DMA_DATA_BURST_8: | 297 | case OMAP_DMA_DATA_BURST_8: |
227 | /* not supported by current hardware | 298 | /* not supported by current hardware |
@@ -231,110 +302,283 @@ void omap_set_dma_src_burst_mode(int lch, enum omap_dma_burst_mode burst_mode) | |||
231 | default: | 302 | default: |
232 | BUG(); | 303 | BUG(); |
233 | } | 304 | } |
234 | omap_writew(w, OMAP_DMA_CSDP(lch)); | ||
235 | } | 305 | } |
236 | 306 | ||
307 | /* Note that dest_port is only for OMAP1 */ | ||
237 | void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode, | 308 | void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode, |
238 | unsigned long dest_start) | 309 | unsigned long dest_start, |
310 | int dst_ei, int dst_fi) | ||
239 | { | 311 | { |
240 | u16 w; | 312 | if (cpu_class_is_omap1()) { |
313 | OMAP_DMA_CSDP_REG(lch) &= ~(0x1f << 9); | ||
314 | OMAP_DMA_CSDP_REG(lch) |= dest_port << 9; | ||
315 | } | ||
241 | 316 | ||
242 | w = omap_readw(OMAP_DMA_CSDP(lch)); | 317 | OMAP_DMA_CCR_REG(lch) &= ~(0x03 << 14); |
243 | w &= ~(0x1f << 9); | 318 | OMAP_DMA_CCR_REG(lch) |= dest_amode << 14; |
244 | w |= dest_port << 9; | 319 | |
245 | omap_writew(w, OMAP_DMA_CSDP(lch)); | 320 | if (cpu_class_is_omap1()) { |
321 | OMAP1_DMA_CDSA_U_REG(lch) = dest_start >> 16; | ||
322 | OMAP1_DMA_CDSA_L_REG(lch) = dest_start; | ||
323 | } | ||
246 | 324 | ||
247 | w = omap_readw(OMAP_DMA_CCR(lch)); | 325 | if (cpu_is_omap24xx()) |
248 | w &= ~(0x03 << 14); | 326 | OMAP2_DMA_CDSA_REG(lch) = dest_start; |
249 | w |= dest_amode << 14; | ||
250 | omap_writew(w, OMAP_DMA_CCR(lch)); | ||
251 | 327 | ||
252 | omap_writew(dest_start >> 16, OMAP_DMA_CDSA_U(lch)); | 328 | OMAP_DMA_CDEI_REG(lch) = dst_ei; |
253 | omap_writew(dest_start, OMAP_DMA_CDSA_L(lch)); | 329 | OMAP_DMA_CDFI_REG(lch) = dst_fi; |
254 | } | 330 | } |
255 | 331 | ||
256 | void omap_set_dma_dest_index(int lch, int eidx, int fidx) | 332 | void omap_set_dma_dest_index(int lch, int eidx, int fidx) |
257 | { | 333 | { |
258 | omap_writew(eidx, OMAP_DMA_CDEI(lch)); | 334 | if (cpu_is_omap24xx()) { |
259 | omap_writew(fidx, OMAP_DMA_CDFI(lch)); | 335 | REVISIT_24XX(); |
336 | return; | ||
337 | } | ||
338 | OMAP_DMA_CDEI_REG(lch) = eidx; | ||
339 | OMAP_DMA_CDFI_REG(lch) = fidx; | ||
260 | } | 340 | } |
261 | 341 | ||
262 | void omap_set_dma_dest_data_pack(int lch, int enable) | 342 | void omap_set_dma_dest_data_pack(int lch, int enable) |
263 | { | 343 | { |
264 | u16 w; | 344 | OMAP_DMA_CSDP_REG(lch) &= ~(1 << 13); |
265 | 345 | if (enable) | |
266 | w = omap_readw(OMAP_DMA_CSDP(lch)) & ~(1 << 13); | 346 | OMAP_DMA_CSDP_REG(lch) |= 1 << 13; |
267 | w |= enable ? (1 << 13) : 0; | ||
268 | omap_writew(w, OMAP_DMA_CSDP(lch)); | ||
269 | } | 347 | } |
270 | 348 | ||
271 | void omap_set_dma_dest_burst_mode(int lch, enum omap_dma_burst_mode burst_mode) | 349 | void omap_set_dma_dest_burst_mode(int lch, enum omap_dma_burst_mode burst_mode) |
272 | { | 350 | { |
273 | u16 w; | 351 | OMAP_DMA_CSDP_REG(lch) &= ~(0x03 << 14); |
274 | 352 | ||
275 | w = omap_readw(OMAP_DMA_CSDP(lch)) & ~(0x03 << 14); | ||
276 | switch (burst_mode) { | 353 | switch (burst_mode) { |
277 | case OMAP_DMA_DATA_BURST_DIS: | 354 | case OMAP_DMA_DATA_BURST_DIS: |
278 | break; | 355 | break; |
279 | case OMAP_DMA_DATA_BURST_4: | 356 | case OMAP_DMA_DATA_BURST_4: |
280 | w |= (0x01 << 14); | 357 | OMAP_DMA_CSDP_REG(lch) |= (0x02 << 14); |
281 | break; | 358 | break; |
282 | case OMAP_DMA_DATA_BURST_8: | 359 | case OMAP_DMA_DATA_BURST_8: |
283 | w |= (0x03 << 14); | 360 | OMAP_DMA_CSDP_REG(lch) |= (0x03 << 14); |
284 | break; | 361 | break; |
285 | default: | 362 | default: |
286 | printk(KERN_ERR "Invalid DMA burst mode\n"); | 363 | printk(KERN_ERR "Invalid DMA burst mode\n"); |
287 | BUG(); | 364 | BUG(); |
288 | return; | 365 | return; |
289 | } | 366 | } |
290 | omap_writew(w, OMAP_DMA_CSDP(lch)); | ||
291 | } | 367 | } |
292 | 368 | ||
293 | static inline void init_intr(int lch) | 369 | static inline void omap_enable_channel_irq(int lch) |
294 | { | 370 | { |
295 | u16 w; | 371 | u32 status; |
296 | 372 | ||
297 | /* Read CSR to make sure it's cleared. */ | 373 | /* Read CSR to make sure it's cleared. */ |
298 | w = omap_readw(OMAP_DMA_CSR(lch)); | 374 | status = OMAP_DMA_CSR_REG(lch); |
375 | |||
299 | /* Enable some nice interrupts. */ | 376 | /* Enable some nice interrupts. */ |
300 | omap_writew(dma_chan[lch].enabled_irqs, OMAP_DMA_CICR(lch)); | 377 | OMAP_DMA_CICR_REG(lch) = dma_chan[lch].enabled_irqs; |
378 | |||
301 | dma_chan[lch].flags |= OMAP_DMA_ACTIVE; | 379 | dma_chan[lch].flags |= OMAP_DMA_ACTIVE; |
302 | } | 380 | } |
303 | 381 | ||
304 | static inline void enable_lnk(int lch) | 382 | static void omap_disable_channel_irq(int lch) |
305 | { | 383 | { |
306 | u16 w; | 384 | if (cpu_is_omap24xx()) |
385 | OMAP_DMA_CICR_REG(lch) = 0; | ||
386 | } | ||
387 | |||
388 | void omap_enable_dma_irq(int lch, u16 bits) | ||
389 | { | ||
390 | dma_chan[lch].enabled_irqs |= bits; | ||
391 | } | ||
307 | 392 | ||
308 | /* Clear the STOP_LNK bits */ | 393 | void omap_disable_dma_irq(int lch, u16 bits) |
309 | w = omap_readw(OMAP_DMA_CLNK_CTRL(lch)); | 394 | { |
310 | w &= ~(1 << 14); | 395 | dma_chan[lch].enabled_irqs &= ~bits; |
311 | omap_writew(w, OMAP_DMA_CLNK_CTRL(lch)); | 396 | } |
397 | |||
398 | static inline void enable_lnk(int lch) | ||
399 | { | ||
400 | if (cpu_class_is_omap1()) | ||
401 | OMAP_DMA_CLNK_CTRL_REG(lch) &= ~(1 << 14); | ||
312 | 402 | ||
313 | /* And set the ENABLE_LNK bits */ | 403 | /* Set the ENABLE_LNK bits */ |
314 | if (dma_chan[lch].next_lch != -1) | 404 | if (dma_chan[lch].next_lch != -1) |
315 | omap_writew(dma_chan[lch].next_lch | (1 << 15), | 405 | OMAP_DMA_CLNK_CTRL_REG(lch) = |
316 | OMAP_DMA_CLNK_CTRL(lch)); | 406 | dma_chan[lch].next_lch | (1 << 15); |
317 | } | 407 | } |
318 | 408 | ||
319 | static inline void disable_lnk(int lch) | 409 | static inline void disable_lnk(int lch) |
320 | { | 410 | { |
321 | u16 w; | ||
322 | |||
323 | /* Disable interrupts */ | 411 | /* Disable interrupts */ |
324 | omap_writew(0, OMAP_DMA_CICR(lch)); | 412 | if (cpu_class_is_omap1()) { |
413 | OMAP_DMA_CICR_REG(lch) = 0; | ||
414 | /* Set the STOP_LNK bit */ | ||
415 | OMAP_DMA_CLNK_CTRL_REG(lch) |= 1 << 14; | ||
416 | } | ||
325 | 417 | ||
326 | /* Set the STOP_LNK bit */ | 418 | if (cpu_is_omap24xx()) { |
327 | w = omap_readw(OMAP_DMA_CLNK_CTRL(lch)); | 419 | omap_disable_channel_irq(lch); |
328 | w |= (1 << 14); | 420 | /* Clear the ENABLE_LNK bit */ |
329 | w = omap_writew(w, OMAP_DMA_CLNK_CTRL(lch)); | 421 | OMAP_DMA_CLNK_CTRL_REG(lch) &= ~(1 << 15); |
422 | } | ||
330 | 423 | ||
331 | dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE; | 424 | dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE; |
332 | } | 425 | } |
333 | 426 | ||
334 | void omap_start_dma(int lch) | 427 | static inline void omap2_enable_irq_lch(int lch) |
335 | { | 428 | { |
336 | u16 w; | 429 | u32 val; |
430 | |||
431 | if (!cpu_is_omap24xx()) | ||
432 | return; | ||
433 | |||
434 | val = omap_readl(OMAP_DMA4_IRQENABLE_L0); | ||
435 | val |= 1 << lch; | ||
436 | omap_writel(val, OMAP_DMA4_IRQENABLE_L0); | ||
437 | } | ||
438 | |||
439 | int omap_request_dma(int dev_id, const char *dev_name, | ||
440 | void (* callback)(int lch, u16 ch_status, void *data), | ||
441 | void *data, int *dma_ch_out) | ||
442 | { | ||
443 | int ch, free_ch = -1; | ||
444 | unsigned long flags; | ||
445 | struct omap_dma_lch *chan; | ||
446 | |||
447 | spin_lock_irqsave(&dma_chan_lock, flags); | ||
448 | for (ch = 0; ch < dma_chan_count; ch++) { | ||
449 | if (free_ch == -1 && dma_chan[ch].dev_id == -1) { | ||
450 | free_ch = ch; | ||
451 | if (dev_id == 0) | ||
452 | break; | ||
453 | } | ||
454 | } | ||
455 | if (free_ch == -1) { | ||
456 | spin_unlock_irqrestore(&dma_chan_lock, flags); | ||
457 | return -EBUSY; | ||
458 | } | ||
459 | chan = dma_chan + free_ch; | ||
460 | chan->dev_id = dev_id; | ||
461 | |||
462 | if (cpu_class_is_omap1()) | ||
463 | clear_lch_regs(free_ch); | ||
337 | 464 | ||
465 | if (cpu_is_omap24xx()) | ||
466 | omap_clear_dma(free_ch); | ||
467 | |||
468 | spin_unlock_irqrestore(&dma_chan_lock, flags); | ||
469 | |||
470 | chan->dev_name = dev_name; | ||
471 | chan->callback = callback; | ||
472 | chan->data = data; | ||
473 | chan->enabled_irqs = OMAP_DMA_TOUT_IRQ | OMAP_DMA_DROP_IRQ | | ||
474 | OMAP_DMA_BLOCK_IRQ; | ||
475 | |||
476 | if (cpu_is_omap24xx()) | ||
477 | chan->enabled_irqs |= OMAP2_DMA_TRANS_ERR_IRQ; | ||
478 | |||
479 | if (cpu_is_omap16xx()) { | ||
480 | /* If the sync device is set, configure it dynamically. */ | ||
481 | if (dev_id != 0) { | ||
482 | set_gdma_dev(free_ch + 1, dev_id); | ||
483 | dev_id = free_ch + 1; | ||
484 | } | ||
485 | /* Disable the 1510 compatibility mode and set the sync device | ||
486 | * id. */ | ||
487 | OMAP_DMA_CCR_REG(free_ch) = dev_id | (1 << 10); | ||
488 | } else if (cpu_is_omap730() || cpu_is_omap15xx()) { | ||
489 | OMAP_DMA_CCR_REG(free_ch) = dev_id; | ||
490 | } | ||
491 | |||
492 | if (cpu_is_omap24xx()) { | ||
493 | omap2_enable_irq_lch(free_ch); | ||
494 | |||
495 | omap_enable_channel_irq(free_ch); | ||
496 | /* Clear the CSR register and IRQ status register */ | ||
497 | OMAP_DMA_CSR_REG(free_ch) = 0x0; | ||
498 | omap_writel(~0x0, OMAP_DMA4_IRQSTATUS_L0); | ||
499 | } | ||
500 | |||
501 | *dma_ch_out = free_ch; | ||
502 | |||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | void omap_free_dma(int lch) | ||
507 | { | ||
508 | unsigned long flags; | ||
509 | |||
510 | spin_lock_irqsave(&dma_chan_lock, flags); | ||
511 | if (dma_chan[lch].dev_id == -1) { | ||
512 | printk("omap_dma: trying to free nonallocated DMA channel %d\n", | ||
513 | lch); | ||
514 | spin_unlock_irqrestore(&dma_chan_lock, flags); | ||
515 | return; | ||
516 | } | ||
517 | dma_chan[lch].dev_id = -1; | ||
518 | dma_chan[lch].next_lch = -1; | ||
519 | dma_chan[lch].callback = NULL; | ||
520 | spin_unlock_irqrestore(&dma_chan_lock, flags); | ||
521 | |||
522 | if (cpu_class_is_omap1()) { | ||
523 | /* Disable all DMA interrupts for the channel. */ | ||
524 | OMAP_DMA_CICR_REG(lch) = 0; | ||
525 | /* Make sure the DMA transfer is stopped. */ | ||
526 | OMAP_DMA_CCR_REG(lch) = 0; | ||
527 | } | ||
528 | |||
529 | if (cpu_is_omap24xx()) { | ||
530 | u32 val; | ||
531 | /* Disable interrupts */ | ||
532 | val = omap_readl(OMAP_DMA4_IRQENABLE_L0); | ||
533 | val &= ~(1 << lch); | ||
534 | omap_writel(val, OMAP_DMA4_IRQENABLE_L0); | ||
535 | |||
536 | /* Clear the CSR register and IRQ status register */ | ||
537 | OMAP_DMA_CSR_REG(lch) = 0x0; | ||
538 | |||
539 | val = omap_readl(OMAP_DMA4_IRQSTATUS_L0); | ||
540 | val |= 1 << lch; | ||
541 | omap_writel(val, OMAP_DMA4_IRQSTATUS_L0); | ||
542 | |||
543 | /* Disable all DMA interrupts for the channel. */ | ||
544 | OMAP_DMA_CICR_REG(lch) = 0; | ||
545 | |||
546 | /* Make sure the DMA transfer is stopped. */ | ||
547 | OMAP_DMA_CCR_REG(lch) = 0; | ||
548 | omap_clear_dma(lch); | ||
549 | } | ||
550 | } | ||
551 | |||
552 | /* | ||
553 | * Clears any DMA state so the DMA engine is ready to restart with new buffers | ||
554 | * through omap_start_dma(). Any buffers in flight are discarded. | ||
555 | */ | ||
556 | void omap_clear_dma(int lch) | ||
557 | { | ||
558 | unsigned long flags; | ||
559 | |||
560 | local_irq_save(flags); | ||
561 | |||
562 | if (cpu_class_is_omap1()) { | ||
563 | int status; | ||
564 | OMAP_DMA_CCR_REG(lch) &= ~OMAP_DMA_CCR_EN; | ||
565 | |||
566 | /* Clear pending interrupts */ | ||
567 | status = OMAP_DMA_CSR_REG(lch); | ||
568 | } | ||
569 | |||
570 | if (cpu_is_omap24xx()) { | ||
571 | int i; | ||
572 | u32 lch_base = OMAP24XX_DMA_BASE + lch * 0x60 + 0x80; | ||
573 | for (i = 0; i < 0x44; i += 4) | ||
574 | omap_writel(0, lch_base + i); | ||
575 | } | ||
576 | |||
577 | local_irq_restore(flags); | ||
578 | } | ||
579 | |||
580 | void omap_start_dma(int lch) | ||
581 | { | ||
338 | if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) { | 582 | if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) { |
339 | int next_lch, cur_lch; | 583 | int next_lch, cur_lch; |
340 | char dma_chan_link_map[OMAP_LOGICAL_DMA_CH_COUNT]; | 584 | char dma_chan_link_map[OMAP_LOGICAL_DMA_CH_COUNT]; |
@@ -348,31 +592,37 @@ void omap_start_dma(int lch) | |||
348 | do { | 592 | do { |
349 | next_lch = dma_chan[cur_lch].next_lch; | 593 | next_lch = dma_chan[cur_lch].next_lch; |
350 | 594 | ||
351 | /* The loop case: we've been here already */ | 595 | /* The loop case: we've been here already */ |
352 | if (dma_chan_link_map[cur_lch]) | 596 | if (dma_chan_link_map[cur_lch]) |
353 | break; | 597 | break; |
354 | /* Mark the current channel */ | 598 | /* Mark the current channel */ |
355 | dma_chan_link_map[cur_lch] = 1; | 599 | dma_chan_link_map[cur_lch] = 1; |
356 | 600 | ||
357 | enable_lnk(cur_lch); | 601 | enable_lnk(cur_lch); |
358 | init_intr(cur_lch); | 602 | omap_enable_channel_irq(cur_lch); |
359 | 603 | ||
360 | cur_lch = next_lch; | 604 | cur_lch = next_lch; |
361 | } while (next_lch != -1); | 605 | } while (next_lch != -1); |
606 | } else if (cpu_is_omap24xx()) { | ||
607 | /* Errata: Need to write lch even if not using chaining */ | ||
608 | OMAP_DMA_CLNK_CTRL_REG(lch) = lch; | ||
362 | } | 609 | } |
363 | 610 | ||
364 | init_intr(lch); | 611 | omap_enable_channel_irq(lch); |
612 | |||
613 | /* Errata: On ES2.0 BUFFERING disable must be set. | ||
614 | * This will always fail on ES1.0 */ | ||
615 | if (cpu_is_omap24xx()) { | ||
616 | OMAP_DMA_CCR_REG(lch) |= OMAP_DMA_CCR_EN; | ||
617 | } | ||
618 | |||
619 | OMAP_DMA_CCR_REG(lch) |= OMAP_DMA_CCR_EN; | ||
365 | 620 | ||
366 | w = omap_readw(OMAP_DMA_CCR(lch)); | ||
367 | w |= OMAP_DMA_CCR_EN; | ||
368 | omap_writew(w, OMAP_DMA_CCR(lch)); | ||
369 | dma_chan[lch].flags |= OMAP_DMA_ACTIVE; | 621 | dma_chan[lch].flags |= OMAP_DMA_ACTIVE; |
370 | } | 622 | } |
371 | 623 | ||
372 | void omap_stop_dma(int lch) | 624 | void omap_stop_dma(int lch) |
373 | { | 625 | { |
374 | u16 w; | ||
375 | |||
376 | if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) { | 626 | if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) { |
377 | int next_lch, cur_lch = lch; | 627 | int next_lch, cur_lch = lch; |
378 | char dma_chan_link_map[OMAP_LOGICAL_DMA_CH_COUNT]; | 628 | char dma_chan_link_map[OMAP_LOGICAL_DMA_CH_COUNT]; |
@@ -393,146 +643,83 @@ void omap_stop_dma(int lch) | |||
393 | 643 | ||
394 | return; | 644 | return; |
395 | } | 645 | } |
646 | |||
396 | /* Disable all interrupts on the channel */ | 647 | /* Disable all interrupts on the channel */ |
397 | omap_writew(0, OMAP_DMA_CICR(lch)); | 648 | if (cpu_class_is_omap1()) |
649 | OMAP_DMA_CICR_REG(lch) = 0; | ||
398 | 650 | ||
399 | w = omap_readw(OMAP_DMA_CCR(lch)); | 651 | OMAP_DMA_CCR_REG(lch) &= ~OMAP_DMA_CCR_EN; |
400 | w &= ~OMAP_DMA_CCR_EN; | ||
401 | omap_writew(w, OMAP_DMA_CCR(lch)); | ||
402 | dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE; | 652 | dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE; |
403 | } | 653 | } |
404 | 654 | ||
405 | void omap_enable_dma_irq(int lch, u16 bits) | 655 | /* |
656 | * Returns current physical source address for the given DMA channel. | ||
657 | * If the channel is running the caller must disable interrupts prior calling | ||
658 | * this function and process the returned value before re-enabling interrupt to | ||
659 | * prevent races with the interrupt handler. Note that in continuous mode there | ||
660 | * is a chance for CSSA_L register overflow inbetween the two reads resulting | ||
661 | * in incorrect return value. | ||
662 | */ | ||
663 | dma_addr_t omap_get_dma_src_pos(int lch) | ||
406 | { | 664 | { |
407 | dma_chan[lch].enabled_irqs |= bits; | 665 | dma_addr_t offset; |
408 | } | ||
409 | 666 | ||
410 | void omap_disable_dma_irq(int lch, u16 bits) | 667 | if (cpu_class_is_omap1()) |
411 | { | 668 | offset = (dma_addr_t) (OMAP1_DMA_CSSA_L_REG(lch) | |
412 | dma_chan[lch].enabled_irqs &= ~bits; | 669 | (OMAP1_DMA_CSSA_U_REG(lch) << 16)); |
413 | } | ||
414 | 670 | ||
415 | static int dma_handle_ch(int ch) | 671 | if (cpu_is_omap24xx()) |
416 | { | 672 | offset = OMAP_DMA_CSAC_REG(lch); |
417 | u16 csr; | ||
418 | 673 | ||
419 | if (enable_1510_mode && ch >= 6) { | 674 | return offset; |
420 | csr = dma_chan[ch].saved_csr; | ||
421 | dma_chan[ch].saved_csr = 0; | ||
422 | } else | ||
423 | csr = omap_readw(OMAP_DMA_CSR(ch)); | ||
424 | if (enable_1510_mode && ch <= 2 && (csr >> 7) != 0) { | ||
425 | dma_chan[ch + 6].saved_csr = csr >> 7; | ||
426 | csr &= 0x7f; | ||
427 | } | ||
428 | if ((csr & 0x3f) == 0) | ||
429 | return 0; | ||
430 | if (unlikely(dma_chan[ch].dev_id == -1)) { | ||
431 | printk(KERN_WARNING "Spurious interrupt from DMA channel %d (CSR %04x)\n", | ||
432 | ch, csr); | ||
433 | return 0; | ||
434 | } | ||
435 | if (unlikely(csr & OMAP_DMA_TOUT_IRQ)) | ||
436 | printk(KERN_WARNING "DMA timeout with device %d\n", dma_chan[ch].dev_id); | ||
437 | if (unlikely(csr & OMAP_DMA_DROP_IRQ)) | ||
438 | printk(KERN_WARNING "DMA synchronization event drop occurred with device %d\n", | ||
439 | dma_chan[ch].dev_id); | ||
440 | if (likely(csr & OMAP_DMA_BLOCK_IRQ)) | ||
441 | dma_chan[ch].flags &= ~OMAP_DMA_ACTIVE; | ||
442 | if (likely(dma_chan[ch].callback != NULL)) | ||
443 | dma_chan[ch].callback(ch, csr, dma_chan[ch].data); | ||
444 | return 1; | ||
445 | } | 675 | } |
446 | 676 | ||
447 | static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) | 677 | /* |
678 | * Returns current physical destination address for the given DMA channel. | ||
679 | * If the channel is running the caller must disable interrupts prior calling | ||
680 | * this function and process the returned value before re-enabling interrupt to | ||
681 | * prevent races with the interrupt handler. Note that in continuous mode there | ||
682 | * is a chance for CDSA_L register overflow inbetween the two reads resulting | ||
683 | * in incorrect return value. | ||
684 | */ | ||
685 | dma_addr_t omap_get_dma_dst_pos(int lch) | ||
448 | { | 686 | { |
449 | int ch = ((int) dev_id) - 1; | 687 | dma_addr_t offset; |
450 | int handled = 0; | ||
451 | 688 | ||
452 | for (;;) { | 689 | if (cpu_class_is_omap1()) |
453 | int handled_now = 0; | 690 | offset = (dma_addr_t) (OMAP1_DMA_CDSA_L_REG(lch) | |
691 | (OMAP1_DMA_CDSA_U_REG(lch) << 16)); | ||
454 | 692 | ||
455 | handled_now += dma_handle_ch(ch); | 693 | if (cpu_is_omap24xx()) |
456 | if (enable_1510_mode && dma_chan[ch + 6].saved_csr) | 694 | offset = OMAP2_DMA_CDSA_REG(lch); |
457 | handled_now += dma_handle_ch(ch + 6); | ||
458 | if (!handled_now) | ||
459 | break; | ||
460 | handled += handled_now; | ||
461 | } | ||
462 | 695 | ||
463 | return handled ? IRQ_HANDLED : IRQ_NONE; | 696 | return offset; |
464 | } | 697 | } |
465 | 698 | ||
466 | int omap_request_dma(int dev_id, const char *dev_name, | 699 | /* |
467 | void (* callback)(int lch, u16 ch_status, void *data), | 700 | * Returns current source transfer counting for the given DMA channel. |
468 | void *data, int *dma_ch_out) | 701 | * Can be used to monitor the progress of a transfer inside a block. |
702 | * It must be called with disabled interrupts. | ||
703 | */ | ||
704 | int omap_get_dma_src_addr_counter(int lch) | ||
469 | { | 705 | { |
470 | int ch, free_ch = -1; | 706 | return (dma_addr_t) OMAP_DMA_CSAC_REG(lch); |
471 | unsigned long flags; | ||
472 | struct omap_dma_lch *chan; | ||
473 | |||
474 | spin_lock_irqsave(&dma_chan_lock, flags); | ||
475 | for (ch = 0; ch < dma_chan_count; ch++) { | ||
476 | if (free_ch == -1 && dma_chan[ch].dev_id == -1) { | ||
477 | free_ch = ch; | ||
478 | if (dev_id == 0) | ||
479 | break; | ||
480 | } | ||
481 | } | ||
482 | if (free_ch == -1) { | ||
483 | spin_unlock_irqrestore(&dma_chan_lock, flags); | ||
484 | return -EBUSY; | ||
485 | } | ||
486 | chan = dma_chan + free_ch; | ||
487 | chan->dev_id = dev_id; | ||
488 | clear_lch_regs(free_ch); | ||
489 | spin_unlock_irqrestore(&dma_chan_lock, flags); | ||
490 | |||
491 | chan->dev_id = dev_id; | ||
492 | chan->dev_name = dev_name; | ||
493 | chan->callback = callback; | ||
494 | chan->data = data; | ||
495 | chan->enabled_irqs = OMAP_DMA_TOUT_IRQ | OMAP_DMA_DROP_IRQ | OMAP_DMA_BLOCK_IRQ; | ||
496 | |||
497 | if (cpu_is_omap16xx()) { | ||
498 | /* If the sync device is set, configure it dynamically. */ | ||
499 | if (dev_id != 0) { | ||
500 | set_gdma_dev(free_ch + 1, dev_id); | ||
501 | dev_id = free_ch + 1; | ||
502 | } | ||
503 | /* Disable the 1510 compatibility mode and set the sync device | ||
504 | * id. */ | ||
505 | omap_writew(dev_id | (1 << 10), OMAP_DMA_CCR(free_ch)); | ||
506 | } else { | ||
507 | omap_writew(dev_id, OMAP_DMA_CCR(free_ch)); | ||
508 | } | ||
509 | *dma_ch_out = free_ch; | ||
510 | |||
511 | return 0; | ||
512 | } | 707 | } |
513 | 708 | ||
514 | void omap_free_dma(int ch) | 709 | int omap_dma_running(void) |
515 | { | 710 | { |
516 | unsigned long flags; | 711 | int lch; |
517 | 712 | ||
518 | spin_lock_irqsave(&dma_chan_lock, flags); | 713 | /* Check if LCD DMA is running */ |
519 | if (dma_chan[ch].dev_id == -1) { | 714 | if (cpu_is_omap16xx()) |
520 | printk("omap_dma: trying to free nonallocated DMA channel %d\n", ch); | 715 | if (omap_readw(OMAP1610_DMA_LCD_CCR) & OMAP_DMA_CCR_EN) |
521 | spin_unlock_irqrestore(&dma_chan_lock, flags); | 716 | return 1; |
522 | return; | ||
523 | } | ||
524 | dma_chan[ch].dev_id = -1; | ||
525 | spin_unlock_irqrestore(&dma_chan_lock, flags); | ||
526 | 717 | ||
527 | /* Disable all DMA interrupts for the channel. */ | 718 | for (lch = 0; lch < dma_chan_count; lch++) |
528 | omap_writew(0, OMAP_DMA_CICR(ch)); | 719 | if (OMAP_DMA_CCR_REG(lch) & OMAP_DMA_CCR_EN) |
529 | /* Make sure the DMA transfer is stopped. */ | 720 | return 1; |
530 | omap_writew(0, OMAP_DMA_CCR(ch)); | ||
531 | } | ||
532 | 721 | ||
533 | int omap_dma_in_1510_mode(void) | 722 | return 0; |
534 | { | ||
535 | return enable_1510_mode; | ||
536 | } | 723 | } |
537 | 724 | ||
538 | /* | 725 | /* |
@@ -550,7 +737,8 @@ void omap_dma_link_lch (int lch_head, int lch_queue) | |||
550 | 737 | ||
551 | if ((dma_chan[lch_head].dev_id == -1) || | 738 | if ((dma_chan[lch_head].dev_id == -1) || |
552 | (dma_chan[lch_queue].dev_id == -1)) { | 739 | (dma_chan[lch_queue].dev_id == -1)) { |
553 | printk(KERN_ERR "omap_dma: trying to link non requested channels\n"); | 740 | printk(KERN_ERR "omap_dma: trying to link " |
741 | "non requested channels\n"); | ||
554 | dump_stack(); | 742 | dump_stack(); |
555 | } | 743 | } |
556 | 744 | ||
@@ -570,20 +758,149 @@ void omap_dma_unlink_lch (int lch_head, int lch_queue) | |||
570 | 758 | ||
571 | if (dma_chan[lch_head].next_lch != lch_queue || | 759 | if (dma_chan[lch_head].next_lch != lch_queue || |
572 | dma_chan[lch_head].next_lch == -1) { | 760 | dma_chan[lch_head].next_lch == -1) { |
573 | printk(KERN_ERR "omap_dma: trying to unlink non linked channels\n"); | 761 | printk(KERN_ERR "omap_dma: trying to unlink " |
762 | "non linked channels\n"); | ||
574 | dump_stack(); | 763 | dump_stack(); |
575 | } | 764 | } |
576 | 765 | ||
577 | 766 | ||
578 | if ((dma_chan[lch_head].flags & OMAP_DMA_ACTIVE) || | 767 | if ((dma_chan[lch_head].flags & OMAP_DMA_ACTIVE) || |
579 | (dma_chan[lch_head].flags & OMAP_DMA_ACTIVE)) { | 768 | (dma_chan[lch_head].flags & OMAP_DMA_ACTIVE)) { |
580 | printk(KERN_ERR "omap_dma: You need to stop the DMA channels before unlinking\n"); | 769 | printk(KERN_ERR "omap_dma: You need to stop the DMA channels " |
770 | "before unlinking\n"); | ||
581 | dump_stack(); | 771 | dump_stack(); |
582 | } | 772 | } |
583 | 773 | ||
584 | dma_chan[lch_head].next_lch = -1; | 774 | dma_chan[lch_head].next_lch = -1; |
585 | } | 775 | } |
586 | 776 | ||
777 | /*----------------------------------------------------------------------------*/ | ||
778 | |||
779 | #ifdef CONFIG_ARCH_OMAP1 | ||
780 | |||
781 | static int omap1_dma_handle_ch(int ch) | ||
782 | { | ||
783 | u16 csr; | ||
784 | |||
785 | if (enable_1510_mode && ch >= 6) { | ||
786 | csr = dma_chan[ch].saved_csr; | ||
787 | dma_chan[ch].saved_csr = 0; | ||
788 | } else | ||
789 | csr = OMAP_DMA_CSR_REG(ch); | ||
790 | if (enable_1510_mode && ch <= 2 && (csr >> 7) != 0) { | ||
791 | dma_chan[ch + 6].saved_csr = csr >> 7; | ||
792 | csr &= 0x7f; | ||
793 | } | ||
794 | if ((csr & 0x3f) == 0) | ||
795 | return 0; | ||
796 | if (unlikely(dma_chan[ch].dev_id == -1)) { | ||
797 | printk(KERN_WARNING "Spurious interrupt from DMA channel " | ||
798 | "%d (CSR %04x)\n", ch, csr); | ||
799 | return 0; | ||
800 | } | ||
801 | if (unlikely(csr & OMAP_DMA_TOUT_IRQ)) | ||
802 | printk(KERN_WARNING "DMA timeout with device %d\n", | ||
803 | dma_chan[ch].dev_id); | ||
804 | if (unlikely(csr & OMAP_DMA_DROP_IRQ)) | ||
805 | printk(KERN_WARNING "DMA synchronization event drop occurred " | ||
806 | "with device %d\n", dma_chan[ch].dev_id); | ||
807 | if (likely(csr & OMAP_DMA_BLOCK_IRQ)) | ||
808 | dma_chan[ch].flags &= ~OMAP_DMA_ACTIVE; | ||
809 | if (likely(dma_chan[ch].callback != NULL)) | ||
810 | dma_chan[ch].callback(ch, csr, dma_chan[ch].data); | ||
811 | return 1; | ||
812 | } | ||
813 | |||
814 | static irqreturn_t omap1_dma_irq_handler(int irq, void *dev_id, | ||
815 | struct pt_regs *regs) | ||
816 | { | ||
817 | int ch = ((int) dev_id) - 1; | ||
818 | int handled = 0; | ||
819 | |||
820 | for (;;) { | ||
821 | int handled_now = 0; | ||
822 | |||
823 | handled_now += omap1_dma_handle_ch(ch); | ||
824 | if (enable_1510_mode && dma_chan[ch + 6].saved_csr) | ||
825 | handled_now += omap1_dma_handle_ch(ch + 6); | ||
826 | if (!handled_now) | ||
827 | break; | ||
828 | handled += handled_now; | ||
829 | } | ||
830 | |||
831 | return handled ? IRQ_HANDLED : IRQ_NONE; | ||
832 | } | ||
833 | |||
834 | #else | ||
835 | #define omap1_dma_irq_handler NULL | ||
836 | #endif | ||
837 | |||
838 | #ifdef CONFIG_ARCH_OMAP2 | ||
839 | |||
840 | static int omap2_dma_handle_ch(int ch) | ||
841 | { | ||
842 | u32 status = OMAP_DMA_CSR_REG(ch); | ||
843 | u32 val; | ||
844 | |||
845 | if (!status) | ||
846 | return 0; | ||
847 | if (unlikely(dma_chan[ch].dev_id == -1)) | ||
848 | return 0; | ||
849 | /* REVISIT: According to 24xx TRM, there's no TOUT_IE */ | ||
850 | if (unlikely(status & OMAP_DMA_TOUT_IRQ)) | ||
851 | printk(KERN_INFO "DMA timeout with device %d\n", | ||
852 | dma_chan[ch].dev_id); | ||
853 | if (unlikely(status & OMAP_DMA_DROP_IRQ)) | ||
854 | printk(KERN_INFO | ||
855 | "DMA synchronization event drop occurred with device " | ||
856 | "%d\n", dma_chan[ch].dev_id); | ||
857 | |||
858 | if (unlikely(status & OMAP2_DMA_TRANS_ERR_IRQ)) | ||
859 | printk(KERN_INFO "DMA transaction error with device %d\n", | ||
860 | dma_chan[ch].dev_id); | ||
861 | |||
862 | OMAP_DMA_CSR_REG(ch) = 0x20; | ||
863 | |||
864 | val = omap_readl(OMAP_DMA4_IRQSTATUS_L0); | ||
865 | /* ch in this function is from 0-31 while in register it is 1-32 */ | ||
866 | val = 1 << (ch); | ||
867 | omap_writel(val, OMAP_DMA4_IRQSTATUS_L0); | ||
868 | |||
869 | if (likely(dma_chan[ch].callback != NULL)) | ||
870 | dma_chan[ch].callback(ch, status, dma_chan[ch].data); | ||
871 | |||
872 | return 0; | ||
873 | } | ||
874 | |||
875 | /* STATUS register count is from 1-32 while our is 0-31 */ | ||
876 | static irqreturn_t omap2_dma_irq_handler(int irq, void *dev_id, | ||
877 | struct pt_regs *regs) | ||
878 | { | ||
879 | u32 val; | ||
880 | int i; | ||
881 | |||
882 | val = omap_readl(OMAP_DMA4_IRQSTATUS_L0); | ||
883 | |||
884 | for (i = 1; i <= OMAP_LOGICAL_DMA_CH_COUNT; i++) { | ||
885 | int active = val & (1 << (i - 1)); | ||
886 | if (active) | ||
887 | omap2_dma_handle_ch(i - 1); | ||
888 | } | ||
889 | |||
890 | return IRQ_HANDLED; | ||
891 | } | ||
892 | |||
893 | static struct irqaction omap24xx_dma_irq = { | ||
894 | .name = "DMA", | ||
895 | .handler = omap2_dma_irq_handler, | ||
896 | .flags = SA_INTERRUPT | ||
897 | }; | ||
898 | |||
899 | #else | ||
900 | static struct irqaction omap24xx_dma_irq; | ||
901 | #endif | ||
902 | |||
903 | /*----------------------------------------------------------------------------*/ | ||
587 | 904 | ||
588 | static struct lcd_dma_info { | 905 | static struct lcd_dma_info { |
589 | spinlock_t lock; | 906 | spinlock_t lock; |
@@ -795,7 +1112,7 @@ static void set_b1_regs(void) | |||
795 | /* Always set the source port as SDRAM for now*/ | 1112 | /* Always set the source port as SDRAM for now*/ |
796 | w &= ~(0x03 << 6); | 1113 | w &= ~(0x03 << 6); |
797 | if (lcd_dma.callback != NULL) | 1114 | if (lcd_dma.callback != NULL) |
798 | w |= 1 << 1; /* Block interrupt enable */ | 1115 | w |= 1 << 1; /* Block interrupt enable */ |
799 | else | 1116 | else |
800 | w &= ~(1 << 1); | 1117 | w &= ~(1 << 1); |
801 | omap_writew(w, OMAP1610_DMA_LCD_CTRL); | 1118 | omap_writew(w, OMAP1610_DMA_LCD_CTRL); |
@@ -814,7 +1131,8 @@ static void set_b1_regs(void) | |||
814 | omap_writew(fi, OMAP1610_DMA_LCD_SRC_FI_B1_L); | 1131 | omap_writew(fi, OMAP1610_DMA_LCD_SRC_FI_B1_L); |
815 | } | 1132 | } |
816 | 1133 | ||
817 | static irqreturn_t lcd_dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) | 1134 | static irqreturn_t lcd_dma_irq_handler(int irq, void *dev_id, |
1135 | struct pt_regs *regs) | ||
818 | { | 1136 | { |
819 | u16 w; | 1137 | u16 w; |
820 | 1138 | ||
@@ -870,7 +1188,8 @@ void omap_free_lcd_dma(void) | |||
870 | return; | 1188 | return; |
871 | } | 1189 | } |
872 | if (!enable_1510_mode) | 1190 | if (!enable_1510_mode) |
873 | omap_writew(omap_readw(OMAP1610_DMA_LCD_CCR) & ~1, OMAP1610_DMA_LCD_CCR); | 1191 | omap_writew(omap_readw(OMAP1610_DMA_LCD_CCR) & ~1, |
1192 | OMAP1610_DMA_LCD_CCR); | ||
874 | lcd_dma.reserved = 0; | 1193 | lcd_dma.reserved = 0; |
875 | spin_unlock(&lcd_dma.lock); | 1194 | spin_unlock(&lcd_dma.lock); |
876 | } | 1195 | } |
@@ -939,93 +1258,24 @@ void omap_stop_lcd_dma(void) | |||
939 | omap_writew(w, OMAP1610_DMA_LCD_CTRL); | 1258 | omap_writew(w, OMAP1610_DMA_LCD_CTRL); |
940 | } | 1259 | } |
941 | 1260 | ||
942 | /* | 1261 | /*----------------------------------------------------------------------------*/ |
943 | * Clears any DMA state so the DMA engine is ready to restart with new buffers | ||
944 | * through omap_start_dma(). Any buffers in flight are discarded. | ||
945 | */ | ||
946 | void omap_clear_dma(int lch) | ||
947 | { | ||
948 | unsigned long flags; | ||
949 | int status; | ||
950 | |||
951 | local_irq_save(flags); | ||
952 | omap_writew(omap_readw(OMAP_DMA_CCR(lch)) & ~OMAP_DMA_CCR_EN, | ||
953 | OMAP_DMA_CCR(lch)); | ||
954 | status = OMAP_DMA_CSR(lch); /* clear pending interrupts */ | ||
955 | local_irq_restore(flags); | ||
956 | } | ||
957 | |||
958 | /* | ||
959 | * Returns current physical source address for the given DMA channel. | ||
960 | * If the channel is running the caller must disable interrupts prior calling | ||
961 | * this function and process the returned value before re-enabling interrupt to | ||
962 | * prevent races with the interrupt handler. Note that in continuous mode there | ||
963 | * is a chance for CSSA_L register overflow inbetween the two reads resulting | ||
964 | * in incorrect return value. | ||
965 | */ | ||
966 | dma_addr_t omap_get_dma_src_pos(int lch) | ||
967 | { | ||
968 | return (dma_addr_t) (omap_readw(OMAP_DMA_CSSA_L(lch)) | | ||
969 | (omap_readw(OMAP_DMA_CSSA_U(lch)) << 16)); | ||
970 | } | ||
971 | |||
972 | /* | ||
973 | * Returns current physical destination address for the given DMA channel. | ||
974 | * If the channel is running the caller must disable interrupts prior calling | ||
975 | * this function and process the returned value before re-enabling interrupt to | ||
976 | * prevent races with the interrupt handler. Note that in continuous mode there | ||
977 | * is a chance for CDSA_L register overflow inbetween the two reads resulting | ||
978 | * in incorrect return value. | ||
979 | */ | ||
980 | dma_addr_t omap_get_dma_dst_pos(int lch) | ||
981 | { | ||
982 | return (dma_addr_t) (omap_readw(OMAP_DMA_CDSA_L(lch)) | | ||
983 | (omap_readw(OMAP_DMA_CDSA_U(lch)) << 16)); | ||
984 | } | ||
985 | |||
986 | /* | ||
987 | * Returns current source transfer counting for the given DMA channel. | ||
988 | * Can be used to monitor the progress of a transfer inside a block. | ||
989 | * It must be called with disabled interrupts. | ||
990 | */ | ||
991 | int omap_get_dma_src_addr_counter(int lch) | ||
992 | { | ||
993 | return (dma_addr_t) omap_readw(OMAP_DMA_CSAC(lch)); | ||
994 | } | ||
995 | |||
996 | int omap_dma_running(void) | ||
997 | { | ||
998 | int lch; | ||
999 | |||
1000 | /* Check if LCD DMA is running */ | ||
1001 | if (cpu_is_omap16xx()) | ||
1002 | if (omap_readw(OMAP1610_DMA_LCD_CCR) & OMAP_DMA_CCR_EN) | ||
1003 | return 1; | ||
1004 | |||
1005 | for (lch = 0; lch < dma_chan_count; lch++) { | ||
1006 | u16 w; | ||
1007 | |||
1008 | w = omap_readw(OMAP_DMA_CCR(lch)); | ||
1009 | if (w & OMAP_DMA_CCR_EN) | ||
1010 | return 1; | ||
1011 | } | ||
1012 | return 0; | ||
1013 | } | ||
1014 | 1262 | ||
1015 | static int __init omap_init_dma(void) | 1263 | static int __init omap_init_dma(void) |
1016 | { | 1264 | { |
1017 | int ch, r; | 1265 | int ch, r; |
1018 | 1266 | ||
1019 | if (cpu_is_omap1510()) { | 1267 | if (cpu_is_omap15xx()) { |
1020 | printk(KERN_INFO "DMA support for OMAP1510 initialized\n"); | 1268 | printk(KERN_INFO "DMA support for OMAP15xx initialized\n"); |
1021 | dma_chan_count = 9; | 1269 | dma_chan_count = 9; |
1022 | enable_1510_mode = 1; | 1270 | enable_1510_mode = 1; |
1023 | } else if (cpu_is_omap16xx() || cpu_is_omap730()) { | 1271 | } else if (cpu_is_omap16xx() || cpu_is_omap730()) { |
1024 | printk(KERN_INFO "OMAP DMA hardware version %d\n", | 1272 | printk(KERN_INFO "OMAP DMA hardware version %d\n", |
1025 | omap_readw(OMAP_DMA_HW_ID)); | 1273 | omap_readw(OMAP_DMA_HW_ID)); |
1026 | printk(KERN_INFO "DMA capabilities: %08x:%08x:%04x:%04x:%04x\n", | 1274 | printk(KERN_INFO "DMA capabilities: %08x:%08x:%04x:%04x:%04x\n", |
1027 | (omap_readw(OMAP_DMA_CAPS_0_U) << 16) | omap_readw(OMAP_DMA_CAPS_0_L), | 1275 | (omap_readw(OMAP_DMA_CAPS_0_U) << 16) | |
1028 | (omap_readw(OMAP_DMA_CAPS_1_U) << 16) | omap_readw(OMAP_DMA_CAPS_1_L), | 1276 | omap_readw(OMAP_DMA_CAPS_0_L), |
1277 | (omap_readw(OMAP_DMA_CAPS_1_U) << 16) | | ||
1278 | omap_readw(OMAP_DMA_CAPS_1_L), | ||
1029 | omap_readw(OMAP_DMA_CAPS_2), omap_readw(OMAP_DMA_CAPS_3), | 1279 | omap_readw(OMAP_DMA_CAPS_2), omap_readw(OMAP_DMA_CAPS_3), |
1030 | omap_readw(OMAP_DMA_CAPS_4)); | 1280 | omap_readw(OMAP_DMA_CAPS_4)); |
1031 | if (!enable_1510_mode) { | 1281 | if (!enable_1510_mode) { |
@@ -1038,6 +1288,11 @@ static int __init omap_init_dma(void) | |||
1038 | dma_chan_count = 16; | 1288 | dma_chan_count = 16; |
1039 | } else | 1289 | } else |
1040 | dma_chan_count = 9; | 1290 | dma_chan_count = 9; |
1291 | } else if (cpu_is_omap24xx()) { | ||
1292 | u8 revision = omap_readb(OMAP_DMA4_REVISION); | ||
1293 | printk(KERN_INFO "OMAP DMA hardware revision %d.%d\n", | ||
1294 | revision >> 4, revision & 0xf); | ||
1295 | dma_chan_count = OMAP_LOGICAL_DMA_CH_COUNT; | ||
1041 | } else { | 1296 | } else { |
1042 | dma_chan_count = 0; | 1297 | dma_chan_count = 0; |
1043 | return 0; | 1298 | return 0; |
@@ -1049,41 +1304,56 @@ static int __init omap_init_dma(void) | |||
1049 | memset(&dma_chan, 0, sizeof(dma_chan)); | 1304 | memset(&dma_chan, 0, sizeof(dma_chan)); |
1050 | 1305 | ||
1051 | for (ch = 0; ch < dma_chan_count; ch++) { | 1306 | for (ch = 0; ch < dma_chan_count; ch++) { |
1307 | omap_clear_dma(ch); | ||
1052 | dma_chan[ch].dev_id = -1; | 1308 | dma_chan[ch].dev_id = -1; |
1053 | dma_chan[ch].next_lch = -1; | 1309 | dma_chan[ch].next_lch = -1; |
1054 | 1310 | ||
1055 | if (ch >= 6 && enable_1510_mode) | 1311 | if (ch >= 6 && enable_1510_mode) |
1056 | continue; | 1312 | continue; |
1057 | 1313 | ||
1058 | /* request_irq() doesn't like dev_id (ie. ch) being zero, | 1314 | if (cpu_class_is_omap1()) { |
1059 | * so we have to kludge around this. */ | 1315 | /* request_irq() doesn't like dev_id (ie. ch) being |
1060 | r = request_irq(dma_irq[ch], dma_irq_handler, 0, "DMA", | 1316 | * zero, so we have to kludge around this. */ |
1061 | (void *) (ch + 1)); | 1317 | r = request_irq(omap1_dma_irq[ch], |
1318 | omap1_dma_irq_handler, 0, "DMA", | ||
1319 | (void *) (ch + 1)); | ||
1320 | if (r != 0) { | ||
1321 | int i; | ||
1322 | |||
1323 | printk(KERN_ERR "unable to request IRQ %d " | ||
1324 | "for DMA (error %d)\n", | ||
1325 | omap1_dma_irq[ch], r); | ||
1326 | for (i = 0; i < ch; i++) | ||
1327 | free_irq(omap1_dma_irq[i], | ||
1328 | (void *) (i + 1)); | ||
1329 | return r; | ||
1330 | } | ||
1331 | } | ||
1332 | } | ||
1333 | |||
1334 | if (cpu_is_omap24xx()) | ||
1335 | setup_irq(INT_24XX_SDMA_IRQ0, &omap24xx_dma_irq); | ||
1336 | |||
1337 | /* FIXME: Update LCD DMA to work on 24xx */ | ||
1338 | if (cpu_class_is_omap1()) { | ||
1339 | r = request_irq(INT_DMA_LCD, lcd_dma_irq_handler, 0, | ||
1340 | "LCD DMA", NULL); | ||
1062 | if (r != 0) { | 1341 | if (r != 0) { |
1063 | int i; | 1342 | int i; |
1064 | 1343 | ||
1065 | printk(KERN_ERR "unable to request IRQ %d for DMA (error %d)\n", | 1344 | printk(KERN_ERR "unable to request IRQ for LCD DMA " |
1066 | dma_irq[ch], r); | 1345 | "(error %d)\n", r); |
1067 | for (i = 0; i < ch; i++) | 1346 | for (i = 0; i < dma_chan_count; i++) |
1068 | free_irq(dma_irq[i], (void *) (i + 1)); | 1347 | free_irq(omap1_dma_irq[i], (void *) (i + 1)); |
1069 | return r; | 1348 | return r; |
1070 | } | 1349 | } |
1071 | } | 1350 | } |
1072 | r = request_irq(INT_DMA_LCD, lcd_dma_irq_handler, 0, "LCD DMA", NULL); | ||
1073 | if (r != 0) { | ||
1074 | int i; | ||
1075 | 1351 | ||
1076 | printk(KERN_ERR "unable to request IRQ for LCD DMA (error %d)\n", r); | ||
1077 | for (i = 0; i < dma_chan_count; i++) | ||
1078 | free_irq(dma_irq[i], (void *) (i + 1)); | ||
1079 | return r; | ||
1080 | } | ||
1081 | return 0; | 1352 | return 0; |
1082 | } | 1353 | } |
1083 | 1354 | ||
1084 | arch_initcall(omap_init_dma); | 1355 | arch_initcall(omap_init_dma); |
1085 | 1356 | ||
1086 | |||
1087 | EXPORT_SYMBOL(omap_get_dma_src_pos); | 1357 | EXPORT_SYMBOL(omap_get_dma_src_pos); |
1088 | EXPORT_SYMBOL(omap_get_dma_dst_pos); | 1358 | EXPORT_SYMBOL(omap_get_dma_dst_pos); |
1089 | EXPORT_SYMBOL(omap_get_dma_src_addr_counter); | 1359 | EXPORT_SYMBOL(omap_get_dma_src_addr_counter); |
@@ -1109,6 +1379,8 @@ EXPORT_SYMBOL(omap_set_dma_dest_index); | |||
1109 | EXPORT_SYMBOL(omap_set_dma_dest_data_pack); | 1379 | EXPORT_SYMBOL(omap_set_dma_dest_data_pack); |
1110 | EXPORT_SYMBOL(omap_set_dma_dest_burst_mode); | 1380 | EXPORT_SYMBOL(omap_set_dma_dest_burst_mode); |
1111 | 1381 | ||
1382 | EXPORT_SYMBOL(omap_set_dma_params); | ||
1383 | |||
1112 | EXPORT_SYMBOL(omap_dma_link_lch); | 1384 | EXPORT_SYMBOL(omap_dma_link_lch); |
1113 | EXPORT_SYMBOL(omap_dma_unlink_lch); | 1385 | EXPORT_SYMBOL(omap_dma_unlink_lch); |
1114 | 1386 | ||
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index 55059a24ad41..76f721d85137 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c | |||
@@ -140,7 +140,7 @@ static struct gpio_bank gpio_bank_1610[5] = { | |||
140 | }; | 140 | }; |
141 | #endif | 141 | #endif |
142 | 142 | ||
143 | #ifdef CONFIG_ARCH_OMAP1510 | 143 | #ifdef CONFIG_ARCH_OMAP15XX |
144 | static struct gpio_bank gpio_bank_1510[2] = { | 144 | static struct gpio_bank gpio_bank_1510[2] = { |
145 | { OMAP_MPUIO_BASE, INT_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO }, | 145 | { OMAP_MPUIO_BASE, INT_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO }, |
146 | { OMAP1510_GPIO_BASE, INT_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_1510 } | 146 | { OMAP1510_GPIO_BASE, INT_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_1510 } |
@@ -173,7 +173,7 @@ static int gpio_bank_count; | |||
173 | 173 | ||
174 | static inline struct gpio_bank *get_gpio_bank(int gpio) | 174 | static inline struct gpio_bank *get_gpio_bank(int gpio) |
175 | { | 175 | { |
176 | #ifdef CONFIG_ARCH_OMAP1510 | 176 | #ifdef CONFIG_ARCH_OMAP15XX |
177 | if (cpu_is_omap1510()) { | 177 | if (cpu_is_omap1510()) { |
178 | if (OMAP_GPIO_IS_MPUIO(gpio)) | 178 | if (OMAP_GPIO_IS_MPUIO(gpio)) |
179 | return &gpio_bank[0]; | 179 | return &gpio_bank[0]; |
@@ -222,7 +222,7 @@ static inline int gpio_valid(int gpio) | |||
222 | return -1; | 222 | return -1; |
223 | return 0; | 223 | return 0; |
224 | } | 224 | } |
225 | #ifdef CONFIG_ARCH_OMAP1510 | 225 | #ifdef CONFIG_ARCH_OMAP15XX |
226 | if (cpu_is_omap1510() && gpio < 16) | 226 | if (cpu_is_omap1510() && gpio < 16) |
227 | return 0; | 227 | return 0; |
228 | #endif | 228 | #endif |
@@ -654,7 +654,7 @@ int omap_request_gpio(int gpio) | |||
654 | /* Set trigger to none. You need to enable the trigger after request_irq */ | 654 | /* Set trigger to none. You need to enable the trigger after request_irq */ |
655 | _set_gpio_triggering(bank, get_gpio_index(gpio), IRQT_NOEDGE); | 655 | _set_gpio_triggering(bank, get_gpio_index(gpio), IRQT_NOEDGE); |
656 | 656 | ||
657 | #ifdef CONFIG_ARCH_OMAP1510 | 657 | #ifdef CONFIG_ARCH_OMAP15XX |
658 | if (bank->method == METHOD_GPIO_1510) { | 658 | if (bank->method == METHOD_GPIO_1510) { |
659 | void __iomem *reg; | 659 | void __iomem *reg; |
660 | 660 | ||
@@ -739,7 +739,7 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, | |||
739 | bank = (struct gpio_bank *) desc->data; | 739 | bank = (struct gpio_bank *) desc->data; |
740 | if (bank->method == METHOD_MPUIO) | 740 | if (bank->method == METHOD_MPUIO) |
741 | isr_reg = bank->base + OMAP_MPUIO_GPIO_INT; | 741 | isr_reg = bank->base + OMAP_MPUIO_GPIO_INT; |
742 | #ifdef CONFIG_ARCH_OMAP1510 | 742 | #ifdef CONFIG_ARCH_OMAP15XX |
743 | if (bank->method == METHOD_GPIO_1510) | 743 | if (bank->method == METHOD_GPIO_1510) |
744 | isr_reg = bank->base + OMAP1510_GPIO_INT_STATUS; | 744 | isr_reg = bank->base + OMAP1510_GPIO_INT_STATUS; |
745 | #endif | 745 | #endif |
@@ -774,7 +774,7 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, | |||
774 | d = irq_desc + gpio_irq; | 774 | d = irq_desc + gpio_irq; |
775 | desc_handle_irq(gpio_irq, d, regs); | 775 | desc_handle_irq(gpio_irq, d, regs); |
776 | } | 776 | } |
777 | } | 777 | } |
778 | } | 778 | } |
779 | 779 | ||
780 | static void gpio_ack_irq(unsigned int irq) | 780 | static void gpio_ack_irq(unsigned int irq) |
@@ -837,8 +837,9 @@ static struct irqchip mpuio_irq_chip = { | |||
837 | .unmask = mpuio_unmask_irq | 837 | .unmask = mpuio_unmask_irq |
838 | }; | 838 | }; |
839 | 839 | ||
840 | static int initialized = 0; | 840 | static int initialized; |
841 | static struct clk * gpio_ck = NULL; | 841 | static struct clk * gpio_ick; |
842 | static struct clk * gpio_fck; | ||
842 | 843 | ||
843 | static int __init _omap_gpio_init(void) | 844 | static int __init _omap_gpio_init(void) |
844 | { | 845 | { |
@@ -848,14 +849,26 @@ static int __init _omap_gpio_init(void) | |||
848 | initialized = 1; | 849 | initialized = 1; |
849 | 850 | ||
850 | if (cpu_is_omap1510()) { | 851 | if (cpu_is_omap1510()) { |
851 | gpio_ck = clk_get(NULL, "arm_gpio_ck"); | 852 | gpio_ick = clk_get(NULL, "arm_gpio_ck"); |
852 | if (IS_ERR(gpio_ck)) | 853 | if (IS_ERR(gpio_ick)) |
853 | printk("Could not get arm_gpio_ck\n"); | 854 | printk("Could not get arm_gpio_ck\n"); |
854 | else | 855 | else |
855 | clk_use(gpio_ck); | 856 | clk_use(gpio_ick); |
857 | } | ||
858 | if (cpu_is_omap24xx()) { | ||
859 | gpio_ick = clk_get(NULL, "gpios_ick"); | ||
860 | if (IS_ERR(gpio_ick)) | ||
861 | printk("Could not get gpios_ick\n"); | ||
862 | else | ||
863 | clk_use(gpio_ick); | ||
864 | gpio_fck = clk_get(NULL, "gpios_fck"); | ||
865 | if (IS_ERR(gpio_ick)) | ||
866 | printk("Could not get gpios_fck\n"); | ||
867 | else | ||
868 | clk_use(gpio_fck); | ||
856 | } | 869 | } |
857 | 870 | ||
858 | #ifdef CONFIG_ARCH_OMAP1510 | 871 | #ifdef CONFIG_ARCH_OMAP15XX |
859 | if (cpu_is_omap1510()) { | 872 | if (cpu_is_omap1510()) { |
860 | printk(KERN_INFO "OMAP1510 GPIO hardware\n"); | 873 | printk(KERN_INFO "OMAP1510 GPIO hardware\n"); |
861 | gpio_bank_count = 2; | 874 | gpio_bank_count = 2; |
@@ -901,7 +914,7 @@ static int __init _omap_gpio_init(void) | |||
901 | if (bank->method == METHOD_MPUIO) { | 914 | if (bank->method == METHOD_MPUIO) { |
902 | omap_writew(0xFFFF, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_MASKIT); | 915 | omap_writew(0xFFFF, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_MASKIT); |
903 | } | 916 | } |
904 | #ifdef CONFIG_ARCH_OMAP1510 | 917 | #ifdef CONFIG_ARCH_OMAP15XX |
905 | if (bank->method == METHOD_GPIO_1510) { | 918 | if (bank->method == METHOD_GPIO_1510) { |
906 | __raw_writew(0xffff, bank->base + OMAP1510_GPIO_INT_MASK); | 919 | __raw_writew(0xffff, bank->base + OMAP1510_GPIO_INT_MASK); |
907 | __raw_writew(0x0000, bank->base + OMAP1510_GPIO_INT_STATUS); | 920 | __raw_writew(0x0000, bank->base + OMAP1510_GPIO_INT_STATUS); |
@@ -1038,6 +1051,7 @@ static struct sys_device omap_gpio_device = { | |||
1038 | 1051 | ||
1039 | /* | 1052 | /* |
1040 | * This may get called early from board specific init | 1053 | * This may get called early from board specific init |
1054 | * for boards that have interrupts routed via FPGA. | ||
1041 | */ | 1055 | */ |
1042 | int omap_gpio_init(void) | 1056 | int omap_gpio_init(void) |
1043 | { | 1057 | { |
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index 9c9b7df3faf6..ea9475c86656 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c | |||
@@ -491,17 +491,20 @@ int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int leng | |||
491 | omap_set_dma_transfer_params(mcbsp[id].dma_tx_lch, | 491 | omap_set_dma_transfer_params(mcbsp[id].dma_tx_lch, |
492 | OMAP_DMA_DATA_TYPE_S16, | 492 | OMAP_DMA_DATA_TYPE_S16, |
493 | length >> 1, 1, | 493 | length >> 1, 1, |
494 | OMAP_DMA_SYNC_ELEMENT); | 494 | OMAP_DMA_SYNC_ELEMENT, |
495 | 0, 0); | ||
495 | 496 | ||
496 | omap_set_dma_dest_params(mcbsp[id].dma_tx_lch, | 497 | omap_set_dma_dest_params(mcbsp[id].dma_tx_lch, |
497 | OMAP_DMA_PORT_TIPB, | 498 | OMAP_DMA_PORT_TIPB, |
498 | OMAP_DMA_AMODE_CONSTANT, | 499 | OMAP_DMA_AMODE_CONSTANT, |
499 | mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1); | 500 | mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1, |
501 | 0, 0); | ||
500 | 502 | ||
501 | omap_set_dma_src_params(mcbsp[id].dma_tx_lch, | 503 | omap_set_dma_src_params(mcbsp[id].dma_tx_lch, |
502 | OMAP_DMA_PORT_EMIFF, | 504 | OMAP_DMA_PORT_EMIFF, |
503 | OMAP_DMA_AMODE_POST_INC, | 505 | OMAP_DMA_AMODE_POST_INC, |
504 | buffer); | 506 | buffer, |
507 | 0, 0); | ||
505 | 508 | ||
506 | omap_start_dma(mcbsp[id].dma_tx_lch); | 509 | omap_start_dma(mcbsp[id].dma_tx_lch); |
507 | wait_for_completion(&(mcbsp[id].tx_dma_completion)); | 510 | wait_for_completion(&(mcbsp[id].tx_dma_completion)); |
@@ -531,17 +534,20 @@ int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int leng | |||
531 | omap_set_dma_transfer_params(mcbsp[id].dma_rx_lch, | 534 | omap_set_dma_transfer_params(mcbsp[id].dma_rx_lch, |
532 | OMAP_DMA_DATA_TYPE_S16, | 535 | OMAP_DMA_DATA_TYPE_S16, |
533 | length >> 1, 1, | 536 | length >> 1, 1, |
534 | OMAP_DMA_SYNC_ELEMENT); | 537 | OMAP_DMA_SYNC_ELEMENT, |
538 | 0, 0); | ||
535 | 539 | ||
536 | omap_set_dma_src_params(mcbsp[id].dma_rx_lch, | 540 | omap_set_dma_src_params(mcbsp[id].dma_rx_lch, |
537 | OMAP_DMA_PORT_TIPB, | 541 | OMAP_DMA_PORT_TIPB, |
538 | OMAP_DMA_AMODE_CONSTANT, | 542 | OMAP_DMA_AMODE_CONSTANT, |
539 | mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1); | 543 | mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1, |
544 | 0, 0); | ||
540 | 545 | ||
541 | omap_set_dma_dest_params(mcbsp[id].dma_rx_lch, | 546 | omap_set_dma_dest_params(mcbsp[id].dma_rx_lch, |
542 | OMAP_DMA_PORT_EMIFF, | 547 | OMAP_DMA_PORT_EMIFF, |
543 | OMAP_DMA_AMODE_POST_INC, | 548 | OMAP_DMA_AMODE_POST_INC, |
544 | buffer); | 549 | buffer, |
550 | 0, 0); | ||
545 | 551 | ||
546 | omap_start_dma(mcbsp[id].dma_rx_lch); | 552 | omap_start_dma(mcbsp[id].dma_rx_lch); |
547 | wait_for_completion(&(mcbsp[id].rx_dma_completion)); | 553 | wait_for_completion(&(mcbsp[id].rx_dma_completion)); |
@@ -643,7 +649,7 @@ static const struct omap_mcbsp_info mcbsp_730[] = { | |||
643 | }; | 649 | }; |
644 | #endif | 650 | #endif |
645 | 651 | ||
646 | #ifdef CONFIG_ARCH_OMAP1510 | 652 | #ifdef CONFIG_ARCH_OMAP15XX |
647 | static const struct omap_mcbsp_info mcbsp_1510[] = { | 653 | static const struct omap_mcbsp_info mcbsp_1510[] = { |
648 | [0] = { .virt_base = OMAP1510_MCBSP1_BASE, | 654 | [0] = { .virt_base = OMAP1510_MCBSP1_BASE, |
649 | .dma_rx_sync = OMAP_DMA_MCBSP1_RX, | 655 | .dma_rx_sync = OMAP_DMA_MCBSP1_RX, |
@@ -712,7 +718,7 @@ static int __init omap_mcbsp_init(void) | |||
712 | mcbsp_count = ARRAY_SIZE(mcbsp_730); | 718 | mcbsp_count = ARRAY_SIZE(mcbsp_730); |
713 | } | 719 | } |
714 | #endif | 720 | #endif |
715 | #ifdef CONFIG_ARCH_OMAP1510 | 721 | #ifdef CONFIG_ARCH_OMAP15XX |
716 | if (cpu_is_omap1510()) { | 722 | if (cpu_is_omap1510()) { |
717 | mcbsp_info = mcbsp_1510; | 723 | mcbsp_info = mcbsp_1510; |
718 | mcbsp_count = ARRAY_SIZE(mcbsp_1510); | 724 | mcbsp_count = ARRAY_SIZE(mcbsp_1510); |
diff --git a/arch/arm/plat-omap/mux.c b/arch/arm/plat-omap/mux.c index 64482040f89e..8c1c016aa689 100644 --- a/arch/arm/plat-omap/mux.c +++ b/arch/arm/plat-omap/mux.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Utility to set the Omap MUX and PULL_DWN registers from a table in mux.h | 4 | * Utility to set the Omap MUX and PULL_DWN registers from a table in mux.h |
5 | * | 5 | * |
6 | * Copyright (C) 2003 Nokia Corporation | 6 | * Copyright (C) 2003 - 2005 Nokia Corporation |
7 | * | 7 | * |
8 | * Written by Tony Lindgren <tony.lindgren@nokia.com> | 8 | * Written by Tony Lindgren <tony.lindgren@nokia.com> |
9 | * | 9 | * |
@@ -25,38 +25,74 @@ | |||
25 | #include <linux/config.h> | 25 | #include <linux/config.h> |
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/init.h> | 27 | #include <linux/init.h> |
28 | #include <linux/kernel.h> | ||
28 | #include <asm/system.h> | 29 | #include <asm/system.h> |
29 | #include <asm/io.h> | 30 | #include <asm/io.h> |
30 | #include <linux/spinlock.h> | 31 | #include <linux/spinlock.h> |
31 | |||
32 | #define __MUX_C__ | ||
33 | #include <asm/arch/mux.h> | 32 | #include <asm/arch/mux.h> |
34 | 33 | ||
35 | #ifdef CONFIG_OMAP_MUX | 34 | #ifdef CONFIG_OMAP_MUX |
36 | 35 | ||
36 | #define OMAP24XX_L4_BASE 0x48000000 | ||
37 | #define OMAP24XX_PULL_ENA (1 << 3) | ||
38 | #define OMAP24XX_PULL_UP (1 << 4) | ||
39 | |||
40 | static struct pin_config * pin_table; | ||
41 | static unsigned long pin_table_sz; | ||
42 | |||
43 | extern struct pin_config * omap730_pins; | ||
44 | extern struct pin_config * omap1xxx_pins; | ||
45 | extern struct pin_config * omap24xx_pins; | ||
46 | |||
47 | int __init omap_mux_register(struct pin_config * pins, unsigned long size) | ||
48 | { | ||
49 | pin_table = pins; | ||
50 | pin_table_sz = size; | ||
51 | |||
52 | return 0; | ||
53 | } | ||
54 | |||
37 | /* | 55 | /* |
38 | * Sets the Omap MUX and PULL_DWN registers based on the table | 56 | * Sets the Omap MUX and PULL_DWN registers based on the table |
39 | */ | 57 | */ |
40 | int __init_or_module | 58 | int __init_or_module omap_cfg_reg(const unsigned long index) |
41 | omap_cfg_reg(const reg_cfg_t reg_cfg) | ||
42 | { | 59 | { |
43 | static DEFINE_SPINLOCK(mux_spin_lock); | 60 | static DEFINE_SPINLOCK(mux_spin_lock); |
44 | 61 | ||
45 | unsigned long flags; | 62 | unsigned long flags; |
46 | reg_cfg_set *cfg; | 63 | struct pin_config *cfg; |
47 | unsigned int reg_orig = 0, reg = 0, pu_pd_orig = 0, pu_pd = 0, | 64 | unsigned int reg_orig = 0, reg = 0, pu_pd_orig = 0, pu_pd = 0, |
48 | pull_orig = 0, pull = 0; | 65 | pull_orig = 0, pull = 0; |
49 | unsigned int mask, warn = 0; | 66 | unsigned int mask, warn = 0; |
50 | 67 | ||
51 | if (cpu_is_omap7xx()) | 68 | if (!pin_table) |
52 | return 0; | 69 | BUG(); |
53 | 70 | ||
54 | if (reg_cfg > ARRAY_SIZE(reg_cfg_table)) { | 71 | if (index >= pin_table_sz) { |
55 | printk(KERN_ERR "MUX: reg_cfg %d\n", reg_cfg); | 72 | printk(KERN_ERR "Invalid pin mux index: %lu (%lu)\n", |
56 | return -EINVAL; | 73 | index, pin_table_sz); |
74 | dump_stack(); | ||
75 | return -ENODEV; | ||
57 | } | 76 | } |
58 | 77 | ||
59 | cfg = (reg_cfg_set *)®_cfg_table[reg_cfg]; | 78 | cfg = (struct pin_config *)&pin_table[index]; |
79 | if (cpu_is_omap24xx()) { | ||
80 | u8 reg = 0; | ||
81 | |||
82 | reg |= cfg->mask & 0x7; | ||
83 | if (cfg->pull_val) | ||
84 | reg |= OMAP24XX_PULL_ENA; | ||
85 | if(cfg->pu_pd_val) | ||
86 | reg |= OMAP24XX_PULL_UP; | ||
87 | #ifdef CONFIG_OMAP_MUX_DEBUG | ||
88 | printk("Muxing %s (0x%08x): 0x%02x -> 0x%02x\n", | ||
89 | cfg->name, OMAP24XX_L4_BASE + cfg->mux_reg, | ||
90 | omap_readb(OMAP24XX_L4_BASE + cfg->mux_reg), reg); | ||
91 | #endif | ||
92 | omap_writeb(reg, OMAP24XX_L4_BASE + cfg->mux_reg); | ||
93 | |||
94 | return 0; | ||
95 | } | ||
60 | 96 | ||
61 | /* Check the mux register in question */ | 97 | /* Check the mux register in question */ |
62 | if (cfg->mux_reg) { | 98 | if (cfg->mux_reg) { |
@@ -157,7 +193,8 @@ omap_cfg_reg(const reg_cfg_t reg_cfg) | |||
157 | return 0; | 193 | return 0; |
158 | #endif | 194 | #endif |
159 | } | 195 | } |
160 | |||
161 | EXPORT_SYMBOL(omap_cfg_reg); | 196 | EXPORT_SYMBOL(omap_cfg_reg); |
162 | 197 | #else | |
198 | #define omap_mux_init() do {} while(0) | ||
199 | #define omap_cfg_reg(x) do {} while(0) | ||
163 | #endif /* CONFIG_OMAP_MUX */ | 200 | #endif /* CONFIG_OMAP_MUX */ |
diff --git a/arch/arm/plat-omap/pm.c b/arch/arm/plat-omap/pm.c index e15c6c1ddec9..966cca031ca7 100644 --- a/arch/arm/plat-omap/pm.c +++ b/arch/arm/plat-omap/pm.c | |||
@@ -54,11 +54,12 @@ | |||
54 | #include <asm/arch/tps65010.h> | 54 | #include <asm/arch/tps65010.h> |
55 | #include <asm/arch/dsp_common.h> | 55 | #include <asm/arch/dsp_common.h> |
56 | 56 | ||
57 | #include "clock.h" | 57 | #include <asm/arch/clock.h> |
58 | #include "sram.h" | 58 | #include <asm/arch/sram.h> |
59 | 59 | ||
60 | static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE]; | 60 | static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE]; |
61 | static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE]; | 61 | static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE]; |
62 | static unsigned int mpui730_sleep_save[MPUI730_SLEEP_SAVE_SIZE]; | ||
62 | static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE]; | 63 | static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE]; |
63 | static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE]; | 64 | static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE]; |
64 | 65 | ||
@@ -120,8 +121,8 @@ void omap_pm_idle(void) | |||
120 | */ | 121 | */ |
121 | static void omap_pm_wakeup_setup(void) | 122 | static void omap_pm_wakeup_setup(void) |
122 | { | 123 | { |
123 | u32 level1_wake = OMAP_IRQ_BIT(INT_IH2_IRQ); | 124 | u32 level1_wake = 0; |
124 | u32 level2_wake = OMAP_IRQ_BIT(INT_UART2) | OMAP_IRQ_BIT(INT_KEYBOARD); | 125 | u32 level2_wake = OMAP_IRQ_BIT(INT_UART2); |
125 | 126 | ||
126 | /* | 127 | /* |
127 | * Turn off all interrupts except GPIO bank 1, L1-2nd level cascade, | 128 | * Turn off all interrupts except GPIO bank 1, L1-2nd level cascade, |
@@ -129,19 +130,29 @@ static void omap_pm_wakeup_setup(void) | |||
129 | * drivers must still separately call omap_set_gpio_wakeup() to | 130 | * drivers must still separately call omap_set_gpio_wakeup() to |
130 | * wake up to a GPIO interrupt. | 131 | * wake up to a GPIO interrupt. |
131 | */ | 132 | */ |
132 | if (cpu_is_omap1510() || cpu_is_omap16xx()) | 133 | if (cpu_is_omap730()) |
133 | level1_wake |= OMAP_IRQ_BIT(INT_GPIO_BANK1); | 134 | level1_wake = OMAP_IRQ_BIT(INT_730_GPIO_BANK1) | |
134 | else if (cpu_is_omap730()) | 135 | OMAP_IRQ_BIT(INT_730_IH2_IRQ); |
135 | level1_wake |= OMAP_IRQ_BIT(INT_730_GPIO_BANK1); | 136 | else if (cpu_is_omap1510()) |
137 | level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) | | ||
138 | OMAP_IRQ_BIT(INT_1510_IH2_IRQ); | ||
139 | else if (cpu_is_omap16xx()) | ||
140 | level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) | | ||
141 | OMAP_IRQ_BIT(INT_1610_IH2_IRQ); | ||
136 | 142 | ||
137 | omap_writel(~level1_wake, OMAP_IH1_MIR); | 143 | omap_writel(~level1_wake, OMAP_IH1_MIR); |
138 | 144 | ||
139 | if (cpu_is_omap1510()) | 145 | if (cpu_is_omap730()) { |
146 | omap_writel(~level2_wake, OMAP_IH2_0_MIR); | ||
147 | omap_writel(~(OMAP_IRQ_BIT(INT_730_WAKE_UP_REQ) | OMAP_IRQ_BIT(INT_730_MPUIO_KEYPAD)), OMAP_IH2_1_MIR); | ||
148 | } else if (cpu_is_omap1510()) { | ||
149 | level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD); | ||
140 | omap_writel(~level2_wake, OMAP_IH2_MIR); | 150 | omap_writel(~level2_wake, OMAP_IH2_MIR); |
141 | 151 | } else if (cpu_is_omap16xx()) { | |
142 | /* INT_1610_WAKE_UP_REQ is needed for GPIO wakeup... */ | 152 | level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD); |
143 | if (cpu_is_omap16xx()) { | ||
144 | omap_writel(~level2_wake, OMAP_IH2_0_MIR); | 153 | omap_writel(~level2_wake, OMAP_IH2_0_MIR); |
154 | |||
155 | /* INT_1610_WAKE_UP_REQ is needed for GPIO wakeup... */ | ||
145 | omap_writel(~OMAP_IRQ_BIT(INT_1610_WAKE_UP_REQ), OMAP_IH2_1_MIR); | 156 | omap_writel(~OMAP_IRQ_BIT(INT_1610_WAKE_UP_REQ), OMAP_IH2_1_MIR); |
146 | omap_writel(~0x0, OMAP_IH2_2_MIR); | 157 | omap_writel(~0x0, OMAP_IH2_2_MIR); |
147 | omap_writel(~0x0, OMAP_IH2_3_MIR); | 158 | omap_writel(~0x0, OMAP_IH2_3_MIR); |
@@ -185,7 +196,17 @@ void omap_pm_suspend(void) | |||
185 | * Save interrupt, MPUI, ARM and UPLD control registers. | 196 | * Save interrupt, MPUI, ARM and UPLD control registers. |
186 | */ | 197 | */ |
187 | 198 | ||
188 | if (cpu_is_omap1510()) { | 199 | if (cpu_is_omap730()) { |
200 | MPUI730_SAVE(OMAP_IH1_MIR); | ||
201 | MPUI730_SAVE(OMAP_IH2_0_MIR); | ||
202 | MPUI730_SAVE(OMAP_IH2_1_MIR); | ||
203 | MPUI730_SAVE(MPUI_CTRL); | ||
204 | MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG); | ||
205 | MPUI730_SAVE(MPUI_DSP_API_CONFIG); | ||
206 | MPUI730_SAVE(EMIFS_CONFIG); | ||
207 | MPUI730_SAVE(EMIFF_SDRAM_CONFIG); | ||
208 | |||
209 | } else if (cpu_is_omap1510()) { | ||
189 | MPUI1510_SAVE(OMAP_IH1_MIR); | 210 | MPUI1510_SAVE(OMAP_IH1_MIR); |
190 | MPUI1510_SAVE(OMAP_IH2_MIR); | 211 | MPUI1510_SAVE(OMAP_IH2_MIR); |
191 | MPUI1510_SAVE(MPUI_CTRL); | 212 | MPUI1510_SAVE(MPUI_CTRL); |
@@ -280,7 +301,13 @@ void omap_pm_suspend(void) | |||
280 | ULPD_RESTORE(ULPD_CLOCK_CTRL); | 301 | ULPD_RESTORE(ULPD_CLOCK_CTRL); |
281 | ULPD_RESTORE(ULPD_STATUS_REQ); | 302 | ULPD_RESTORE(ULPD_STATUS_REQ); |
282 | 303 | ||
283 | if (cpu_is_omap1510()) { | 304 | if (cpu_is_omap730()) { |
305 | MPUI730_RESTORE(EMIFS_CONFIG); | ||
306 | MPUI730_RESTORE(EMIFF_SDRAM_CONFIG); | ||
307 | MPUI730_RESTORE(OMAP_IH1_MIR); | ||
308 | MPUI730_RESTORE(OMAP_IH2_0_MIR); | ||
309 | MPUI730_RESTORE(OMAP_IH2_1_MIR); | ||
310 | } else if (cpu_is_omap1510()) { | ||
284 | MPUI1510_RESTORE(MPUI_CTRL); | 311 | MPUI1510_RESTORE(MPUI_CTRL); |
285 | MPUI1510_RESTORE(MPUI_DSP_BOOT_CONFIG); | 312 | MPUI1510_RESTORE(MPUI_DSP_BOOT_CONFIG); |
286 | MPUI1510_RESTORE(MPUI_DSP_API_CONFIG); | 313 | MPUI1510_RESTORE(MPUI_DSP_API_CONFIG); |
@@ -355,7 +382,14 @@ static int omap_pm_read_proc( | |||
355 | ULPD_SAVE(ULPD_DPLL_CTRL); | 382 | ULPD_SAVE(ULPD_DPLL_CTRL); |
356 | ULPD_SAVE(ULPD_POWER_CTRL); | 383 | ULPD_SAVE(ULPD_POWER_CTRL); |
357 | 384 | ||
358 | if (cpu_is_omap1510()) { | 385 | if (cpu_is_omap730()) { |
386 | MPUI730_SAVE(MPUI_CTRL); | ||
387 | MPUI730_SAVE(MPUI_DSP_STATUS); | ||
388 | MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG); | ||
389 | MPUI730_SAVE(MPUI_DSP_API_CONFIG); | ||
390 | MPUI730_SAVE(EMIFF_SDRAM_CONFIG); | ||
391 | MPUI730_SAVE(EMIFS_CONFIG); | ||
392 | } else if (cpu_is_omap1510()) { | ||
359 | MPUI1510_SAVE(MPUI_CTRL); | 393 | MPUI1510_SAVE(MPUI_CTRL); |
360 | MPUI1510_SAVE(MPUI_DSP_STATUS); | 394 | MPUI1510_SAVE(MPUI_DSP_STATUS); |
361 | MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG); | 395 | MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG); |
@@ -404,7 +438,21 @@ static int omap_pm_read_proc( | |||
404 | ULPD_SHOW(ULPD_STATUS_REQ), | 438 | ULPD_SHOW(ULPD_STATUS_REQ), |
405 | ULPD_SHOW(ULPD_POWER_CTRL)); | 439 | ULPD_SHOW(ULPD_POWER_CTRL)); |
406 | 440 | ||
407 | if (cpu_is_omap1510()) { | 441 | if (cpu_is_omap730()) { |
442 | my_buffer_offset += sprintf(my_base + my_buffer_offset, | ||
443 | "MPUI730_CTRL_REG 0x%-8x \n" | ||
444 | "MPUI730_DSP_STATUS_REG: 0x%-8x \n" | ||
445 | "MPUI730_DSP_BOOT_CONFIG_REG: 0x%-8x \n" | ||
446 | "MPUI730_DSP_API_CONFIG_REG: 0x%-8x \n" | ||
447 | "MPUI730_SDRAM_CONFIG_REG: 0x%-8x \n" | ||
448 | "MPUI730_EMIFS_CONFIG_REG: 0x%-8x \n", | ||
449 | MPUI730_SHOW(MPUI_CTRL), | ||
450 | MPUI730_SHOW(MPUI_DSP_STATUS), | ||
451 | MPUI730_SHOW(MPUI_DSP_BOOT_CONFIG), | ||
452 | MPUI730_SHOW(MPUI_DSP_API_CONFIG), | ||
453 | MPUI730_SHOW(EMIFF_SDRAM_CONFIG), | ||
454 | MPUI730_SHOW(EMIFS_CONFIG)); | ||
455 | } else if (cpu_is_omap1510()) { | ||
408 | my_buffer_offset += sprintf(my_base + my_buffer_offset, | 456 | my_buffer_offset += sprintf(my_base + my_buffer_offset, |
409 | "MPUI1510_CTRL_REG 0x%-8x \n" | 457 | "MPUI1510_CTRL_REG 0x%-8x \n" |
410 | "MPUI1510_DSP_STATUS_REG: 0x%-8x \n" | 458 | "MPUI1510_DSP_STATUS_REG: 0x%-8x \n" |
@@ -553,7 +601,12 @@ static int __init omap_pm_init(void) | |||
553 | * These routines need to be in SRAM as that's the only | 601 | * These routines need to be in SRAM as that's the only |
554 | * memory the MPU can see when it wakes up. | 602 | * memory the MPU can see when it wakes up. |
555 | */ | 603 | */ |
556 | if (cpu_is_omap1510()) { | 604 | if (cpu_is_omap730()) { |
605 | omap_sram_idle = omap_sram_push(omap730_idle_loop_suspend, | ||
606 | omap730_idle_loop_suspend_sz); | ||
607 | omap_sram_suspend = omap_sram_push(omap730_cpu_suspend, | ||
608 | omap730_cpu_suspend_sz); | ||
609 | } else if (cpu_is_omap1510()) { | ||
557 | omap_sram_idle = omap_sram_push(omap1510_idle_loop_suspend, | 610 | omap_sram_idle = omap_sram_push(omap1510_idle_loop_suspend, |
558 | omap1510_idle_loop_suspend_sz); | 611 | omap1510_idle_loop_suspend_sz); |
559 | omap_sram_suspend = omap_sram_push(omap1510_cpu_suspend, | 612 | omap_sram_suspend = omap_sram_push(omap1510_cpu_suspend, |
@@ -572,7 +625,11 @@ static int __init omap_pm_init(void) | |||
572 | 625 | ||
573 | pm_idle = omap_pm_idle; | 626 | pm_idle = omap_pm_idle; |
574 | 627 | ||
575 | setup_irq(INT_1610_WAKE_UP_REQ, &omap_wakeup_irq); | 628 | if (cpu_is_omap730()) |
629 | setup_irq(INT_730_WAKE_UP_REQ, &omap_wakeup_irq); | ||
630 | else if (cpu_is_omap16xx()) | ||
631 | setup_irq(INT_1610_WAKE_UP_REQ, &omap_wakeup_irq); | ||
632 | |||
576 | #if 0 | 633 | #if 0 |
577 | /* --- BEGIN BOARD-DEPENDENT CODE --- */ | 634 | /* --- BEGIN BOARD-DEPENDENT CODE --- */ |
578 | /* Sleepx mask direction */ | 635 | /* Sleepx mask direction */ |
@@ -591,7 +648,9 @@ static int __init omap_pm_init(void) | |||
591 | omap_writew(ULPD_POWER_CTRL_REG_VAL, ULPD_POWER_CTRL); | 648 | omap_writew(ULPD_POWER_CTRL_REG_VAL, ULPD_POWER_CTRL); |
592 | 649 | ||
593 | /* Configure IDLECT3 */ | 650 | /* Configure IDLECT3 */ |
594 | if (cpu_is_omap16xx()) | 651 | if (cpu_is_omap730()) |
652 | omap_writel(OMAP730_IDLECT3_VAL, OMAP730_IDLECT3); | ||
653 | else if (cpu_is_omap16xx()) | ||
595 | omap_writel(OMAP1610_IDLECT3_VAL, OMAP1610_IDLECT3); | 654 | omap_writel(OMAP1610_IDLECT3_VAL, OMAP1610_IDLECT3); |
596 | 655 | ||
597 | pm_set_ops(&omap_pm_ops); | 656 | pm_set_ops(&omap_pm_ops); |
@@ -600,8 +659,10 @@ static int __init omap_pm_init(void) | |||
600 | omap_pm_init_proc(); | 659 | omap_pm_init_proc(); |
601 | #endif | 660 | #endif |
602 | 661 | ||
603 | /* configure LOW_PWR pin */ | 662 | if (cpu_is_omap16xx()) { |
604 | omap_cfg_reg(T20_1610_LOW_PWR); | 663 | /* configure LOW_PWR pin */ |
664 | omap_cfg_reg(T20_1610_LOW_PWR); | ||
665 | } | ||
605 | 666 | ||
606 | return 0; | 667 | return 0; |
607 | } | 668 | } |
diff --git a/arch/arm/plat-omap/sleep.S b/arch/arm/plat-omap/sleep.S index 9f745836f6aa..4cd7d292f854 100644 --- a/arch/arm/plat-omap/sleep.S +++ b/arch/arm/plat-omap/sleep.S | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * linux/arch/arm/plat-omap/sleep.S | 2 | * linux/arch/arm/plat-omap/sleep.S |
3 | * | 3 | * |
4 | * Low-level OMAP1510/1610 sleep/wakeUp support | 4 | * Low-level OMAP730/1510/1610 sleep/wakeUp support |
5 | * | 5 | * |
6 | * Initial SA1110 code: | 6 | * Initial SA1110 code: |
7 | * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com> | 7 | * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com> |
@@ -52,7 +52,57 @@ | |||
52 | * processor specific functions here. | 52 | * processor specific functions here. |
53 | */ | 53 | */ |
54 | 54 | ||
55 | #ifdef CONFIG_ARCH_OMAP1510 | 55 | #if defined(CONFIG_ARCH_OMAP730) |
56 | ENTRY(omap730_idle_loop_suspend) | ||
57 | |||
58 | stmfd sp!, {r0 - r12, lr} @ save registers on stack | ||
59 | |||
60 | @ load base address of ARM_IDLECT1 and ARM_IDLECT2 | ||
61 | mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | ||
62 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | ||
63 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | ||
64 | |||
65 | @ turn off clock domains | ||
66 | @ get ARM_IDLECT2 into r2 | ||
67 | ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | ||
68 | mov r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff | ||
69 | orr r5, r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff00 | ||
70 | strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | ||
71 | |||
72 | @ request ARM idle | ||
73 | @ get ARM_IDLECT1 into r1 | ||
74 | ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | ||
75 | orr r3, r1, #OMAP730_IDLE_LOOP_REQUEST & 0xffff | ||
76 | strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | ||
77 | |||
78 | mov r5, #IDLE_WAIT_CYCLES & 0xff | ||
79 | orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 | ||
80 | l_730: subs r5, r5, #1 | ||
81 | bne l_730 | ||
82 | /* | ||
83 | * Let's wait for the next clock tick to wake us up. | ||
84 | */ | ||
85 | mov r0, #0 | ||
86 | mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt | ||
87 | /* | ||
88 | * omap730_idle_loop_suspend()'s resume point. | ||
89 | * | ||
90 | * It will just start executing here, so we'll restore stuff from the | ||
91 | * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. | ||
92 | */ | ||
93 | |||
94 | @ restore ARM_IDLECT1 and ARM_IDLECT2 and return | ||
95 | @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2 | ||
96 | strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | ||
97 | strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | ||
98 | |||
99 | ldmfd sp!, {r0 - r12, pc} @ restore regs and return | ||
100 | |||
101 | ENTRY(omap730_idle_loop_suspend_sz) | ||
102 | .word . - omap730_idle_loop_suspend | ||
103 | #endif /* CONFIG_ARCH_OMAP730 */ | ||
104 | |||
105 | #ifdef CONFIG_ARCH_OMAP15XX | ||
56 | ENTRY(omap1510_idle_loop_suspend) | 106 | ENTRY(omap1510_idle_loop_suspend) |
57 | 107 | ||
58 | stmfd sp!, {r0 - r12, lr} @ save registers on stack | 108 | stmfd sp!, {r0 - r12, lr} @ save registers on stack |
@@ -100,7 +150,7 @@ l_1510: subs r5, r5, #1 | |||
100 | 150 | ||
101 | ENTRY(omap1510_idle_loop_suspend_sz) | 151 | ENTRY(omap1510_idle_loop_suspend_sz) |
102 | .word . - omap1510_idle_loop_suspend | 152 | .word . - omap1510_idle_loop_suspend |
103 | #endif /* CONFIG_ARCH_OMAP1510 */ | 153 | #endif /* CONFIG_ARCH_OMAP15XX */ |
104 | 154 | ||
105 | #if defined(CONFIG_ARCH_OMAP16XX) | 155 | #if defined(CONFIG_ARCH_OMAP16XX) |
106 | ENTRY(omap1610_idle_loop_suspend) | 156 | ENTRY(omap1610_idle_loop_suspend) |
@@ -169,7 +219,86 @@ ENTRY(omap1610_idle_loop_suspend_sz) | |||
169 | * | 219 | * |
170 | */ | 220 | */ |
171 | 221 | ||
172 | #ifdef CONFIG_ARCH_OMAP1510 | 222 | #if defined(CONFIG_ARCH_OMAP730) |
223 | ENTRY(omap730_cpu_suspend) | ||
224 | |||
225 | @ save registers on stack | ||
226 | stmfd sp!, {r0 - r12, lr} | ||
227 | |||
228 | @ Drain write cache | ||
229 | mov r4, #0 | ||
230 | mcr p15, 0, r0, c7, c10, 4 | ||
231 | nop | ||
232 | |||
233 | @ load base address of Traffic Controller | ||
234 | mov r6, #TCMIF_ASM_BASE & 0xff000000 | ||
235 | orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000 | ||
236 | orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00 | ||
237 | |||
238 | @ prepare to put SDRAM into self-refresh manually | ||
239 | ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | ||
240 | orr r9, r7, #SELF_REFRESH_MODE & 0xff000000 | ||
241 | orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff | ||
242 | str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | ||
243 | |||
244 | @ prepare to put EMIFS to Sleep | ||
245 | ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | ||
246 | orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff | ||
247 | str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | ||
248 | |||
249 | @ load base address of ARM_IDLECT1 and ARM_IDLECT2 | ||
250 | mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | ||
251 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | ||
252 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | ||
253 | |||
254 | @ turn off clock domains | ||
255 | @ do not disable PERCK (0x04) | ||
256 | mov r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff | ||
257 | orr r5, r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff00 | ||
258 | strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | ||
259 | |||
260 | @ request ARM idle | ||
261 | mov r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff | ||
262 | orr r3, r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff00 | ||
263 | strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | ||
264 | |||
265 | @ disable instruction cache | ||
266 | mrc p15, 0, r9, c1, c0, 0 | ||
267 | bic r2, r9, #0x1000 | ||
268 | mcr p15, 0, r2, c1, c0, 0 | ||
269 | nop | ||
270 | |||
271 | /* | ||
272 | * Let's wait for the next wake up event to wake us up. r0 can't be | ||
273 | * used here because r0 holds ARM_IDLECT1 | ||
274 | */ | ||
275 | mov r2, #0 | ||
276 | mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt | ||
277 | /* | ||
278 | * omap730_cpu_suspend()'s resume point. | ||
279 | * | ||
280 | * It will just start executing here, so we'll restore stuff from the | ||
281 | * stack. | ||
282 | */ | ||
283 | @ re-enable Icache | ||
284 | mcr p15, 0, r9, c1, c0, 0 | ||
285 | |||
286 | @ reset the ARM_IDLECT1 and ARM_IDLECT2. | ||
287 | strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | ||
288 | strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | ||
289 | |||
290 | @ Restore EMIFF controls | ||
291 | str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | ||
292 | str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | ||
293 | |||
294 | @ restore regs and return | ||
295 | ldmfd sp!, {r0 - r12, pc} | ||
296 | |||
297 | ENTRY(omap730_cpu_suspend_sz) | ||
298 | .word . - omap730_cpu_suspend | ||
299 | #endif /* CONFIG_ARCH_OMAP730 */ | ||
300 | |||
301 | #ifdef CONFIG_ARCH_OMAP15XX | ||
173 | ENTRY(omap1510_cpu_suspend) | 302 | ENTRY(omap1510_cpu_suspend) |
174 | 303 | ||
175 | @ save registers on stack | 304 | @ save registers on stack |
@@ -241,7 +370,7 @@ l_1510_2: | |||
241 | 370 | ||
242 | ENTRY(omap1510_cpu_suspend_sz) | 371 | ENTRY(omap1510_cpu_suspend_sz) |
243 | .word . - omap1510_cpu_suspend | 372 | .word . - omap1510_cpu_suspend |
244 | #endif /* CONFIG_ARCH_OMAP1510 */ | 373 | #endif /* CONFIG_ARCH_OMAP15XX */ |
245 | 374 | ||
246 | #if defined(CONFIG_ARCH_OMAP16XX) | 375 | #if defined(CONFIG_ARCH_OMAP16XX) |
247 | ENTRY(omap1610_cpu_suspend) | 376 | ENTRY(omap1610_cpu_suspend) |
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c index 7ad69f14a3e7..792f66375830 100644 --- a/arch/arm/plat-omap/sram.c +++ b/arch/arm/plat-omap/sram.c | |||
@@ -20,10 +20,13 @@ | |||
20 | #include <asm/io.h> | 20 | #include <asm/io.h> |
21 | #include <asm/cacheflush.h> | 21 | #include <asm/cacheflush.h> |
22 | 22 | ||
23 | #include "sram.h" | 23 | #include <asm/arch/sram.h> |
24 | |||
25 | #define OMAP1_SRAM_PA 0x20000000 | ||
26 | #define OMAP1_SRAM_VA 0xd0000000 | ||
27 | #define OMAP2_SRAM_PA 0x40200000 | ||
28 | #define OMAP2_SRAM_VA 0xd0000000 | ||
24 | 29 | ||
25 | #define OMAP1_SRAM_BASE 0xd0000000 | ||
26 | #define OMAP1_SRAM_START 0x20000000 | ||
27 | #define SRAM_BOOTLOADER_SZ 0x80 | 30 | #define SRAM_BOOTLOADER_SZ 0x80 |
28 | 31 | ||
29 | static unsigned long omap_sram_base; | 32 | static unsigned long omap_sram_base; |
@@ -31,37 +34,40 @@ static unsigned long omap_sram_size; | |||
31 | static unsigned long omap_sram_ceil; | 34 | static unsigned long omap_sram_ceil; |
32 | 35 | ||
33 | /* | 36 | /* |
34 | * The amount of SRAM depends on the core type: | 37 | * The amount of SRAM depends on the core type. |
35 | * 730 = 200K, 1510 = 512K, 5912 = 256K, 1610 = 16K, 1710 = 16K | ||
36 | * Note that we cannot try to test for SRAM here because writes | 38 | * Note that we cannot try to test for SRAM here because writes |
37 | * to secure SRAM will hang the system. Also the SRAM is not | 39 | * to secure SRAM will hang the system. Also the SRAM is not |
38 | * yet mapped at this point. | 40 | * yet mapped at this point. |
39 | */ | 41 | */ |
40 | void __init omap_detect_sram(void) | 42 | void __init omap_detect_sram(void) |
41 | { | 43 | { |
42 | omap_sram_base = OMAP1_SRAM_BASE; | 44 | if (!cpu_is_omap24xx()) |
45 | omap_sram_base = OMAP1_SRAM_VA; | ||
46 | else | ||
47 | omap_sram_base = OMAP2_SRAM_VA; | ||
43 | 48 | ||
44 | if (cpu_is_omap730()) | 49 | if (cpu_is_omap730()) |
45 | omap_sram_size = 0x32000; | 50 | omap_sram_size = 0x32000; /* 200K */ |
46 | else if (cpu_is_omap1510()) | 51 | else if (cpu_is_omap15xx()) |
47 | omap_sram_size = 0x80000; | 52 | omap_sram_size = 0x30000; /* 192K */ |
48 | else if (cpu_is_omap1610() || cpu_is_omap1621() || cpu_is_omap1710()) | 53 | else if (cpu_is_omap1610() || cpu_is_omap1621() || cpu_is_omap1710()) |
49 | omap_sram_size = 0x4000; | 54 | omap_sram_size = 0x4000; /* 16K */ |
50 | else if (cpu_is_omap1611()) | 55 | else if (cpu_is_omap1611()) |
51 | omap_sram_size = 0x3e800; | 56 | omap_sram_size = 0x3e800; /* 250K */ |
57 | else if (cpu_is_omap2420()) | ||
58 | omap_sram_size = 0xa0014; /* 640K */ | ||
52 | else { | 59 | else { |
53 | printk(KERN_ERR "Could not detect SRAM size\n"); | 60 | printk(KERN_ERR "Could not detect SRAM size\n"); |
54 | omap_sram_size = 0x4000; | 61 | omap_sram_size = 0x4000; |
55 | } | 62 | } |
56 | 63 | ||
57 | printk(KERN_INFO "SRAM size: 0x%lx\n", omap_sram_size); | ||
58 | omap_sram_ceil = omap_sram_base + omap_sram_size; | 64 | omap_sram_ceil = omap_sram_base + omap_sram_size; |
59 | } | 65 | } |
60 | 66 | ||
61 | static struct map_desc omap_sram_io_desc[] __initdata = { | 67 | static struct map_desc omap_sram_io_desc[] __initdata = { |
62 | { /* .length gets filled in at runtime */ | 68 | { /* .length gets filled in at runtime */ |
63 | .virtual = OMAP1_SRAM_BASE, | 69 | .virtual = OMAP1_SRAM_VA, |
64 | .pfn = __phys_to_pfn(OMAP1_SRAM_START), | 70 | .pfn = __phys_to_pfn(OMAP1_SRAM_PA), |
65 | .type = MT_DEVICE | 71 | .type = MT_DEVICE |
66 | } | 72 | } |
67 | }; | 73 | }; |
@@ -76,10 +82,19 @@ void __init omap_map_sram(void) | |||
76 | if (omap_sram_size == 0) | 82 | if (omap_sram_size == 0) |
77 | return; | 83 | return; |
78 | 84 | ||
85 | if (cpu_is_omap24xx()) { | ||
86 | omap_sram_io_desc[0].virtual = OMAP2_SRAM_VA; | ||
87 | omap_sram_io_desc[0].pfn = __phys_to_pfn(OMAP2_SRAM_PA); | ||
88 | } | ||
89 | |||
79 | omap_sram_io_desc[0].length = (omap_sram_size + PAGE_SIZE-1)/PAGE_SIZE; | 90 | omap_sram_io_desc[0].length = (omap_sram_size + PAGE_SIZE-1)/PAGE_SIZE; |
80 | omap_sram_io_desc[0].length *= PAGE_SIZE; | 91 | omap_sram_io_desc[0].length *= PAGE_SIZE; |
81 | iotable_init(omap_sram_io_desc, ARRAY_SIZE(omap_sram_io_desc)); | 92 | iotable_init(omap_sram_io_desc, ARRAY_SIZE(omap_sram_io_desc)); |
82 | 93 | ||
94 | printk(KERN_INFO "SRAM: Mapped pa 0x%08lx to va 0x%08lx size: 0x%lx\n", | ||
95 | omap_sram_io_desc[0].pfn, omap_sram_io_desc[0].virtual, | ||
96 | omap_sram_io_desc[0].length); | ||
97 | |||
83 | /* | 98 | /* |
84 | * Looks like we need to preserve some bootloader code at the | 99 | * Looks like we need to preserve some bootloader code at the |
85 | * beginning of SRAM for jumping to flash for reboot to work... | 100 | * beginning of SRAM for jumping to flash for reboot to work... |
@@ -88,16 +103,6 @@ void __init omap_map_sram(void) | |||
88 | omap_sram_size - SRAM_BOOTLOADER_SZ); | 103 | omap_sram_size - SRAM_BOOTLOADER_SZ); |
89 | } | 104 | } |
90 | 105 | ||
91 | static void (*_omap_sram_reprogram_clock)(u32 dpllctl, u32 ckctl) = NULL; | ||
92 | |||
93 | void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl) | ||
94 | { | ||
95 | if (_omap_sram_reprogram_clock == NULL) | ||
96 | panic("Cannot use SRAM"); | ||
97 | |||
98 | return _omap_sram_reprogram_clock(dpllctl, ckctl); | ||
99 | } | ||
100 | |||
101 | void * omap_sram_push(void * start, unsigned long size) | 106 | void * omap_sram_push(void * start, unsigned long size) |
102 | { | 107 | { |
103 | if (size > (omap_sram_ceil - (omap_sram_base + SRAM_BOOTLOADER_SZ))) { | 108 | if (size > (omap_sram_ceil - (omap_sram_base + SRAM_BOOTLOADER_SZ))) { |
@@ -111,10 +116,94 @@ void * omap_sram_push(void * start, unsigned long size) | |||
111 | return (void *)omap_sram_ceil; | 116 | return (void *)omap_sram_ceil; |
112 | } | 117 | } |
113 | 118 | ||
114 | void __init omap_sram_init(void) | 119 | static void omap_sram_error(void) |
120 | { | ||
121 | panic("Uninitialized SRAM function\n"); | ||
122 | } | ||
123 | |||
124 | #ifdef CONFIG_ARCH_OMAP1 | ||
125 | |||
126 | static void (*_omap_sram_reprogram_clock)(u32 dpllctl, u32 ckctl); | ||
127 | |||
128 | void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl) | ||
129 | { | ||
130 | if (!_omap_sram_reprogram_clock) | ||
131 | omap_sram_error(); | ||
132 | |||
133 | return _omap_sram_reprogram_clock(dpllctl, ckctl); | ||
134 | } | ||
135 | |||
136 | int __init omap1_sram_init(void) | ||
115 | { | 137 | { |
116 | omap_detect_sram(); | ||
117 | omap_map_sram(); | ||
118 | _omap_sram_reprogram_clock = omap_sram_push(sram_reprogram_clock, | 138 | _omap_sram_reprogram_clock = omap_sram_push(sram_reprogram_clock, |
119 | sram_reprogram_clock_sz); | 139 | sram_reprogram_clock_sz); |
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | #else | ||
145 | #define omap1_sram_init() do {} while (0) | ||
146 | #endif | ||
147 | |||
148 | #ifdef CONFIG_ARCH_OMAP2 | ||
149 | |||
150 | static void (*_omap2_sram_ddr_init)(u32 *slow_dll_ctrl, u32 fast_dll_ctrl, | ||
151 | u32 base_cs, u32 force_unlock); | ||
152 | |||
153 | void omap2_sram_ddr_init(u32 *slow_dll_ctrl, u32 fast_dll_ctrl, | ||
154 | u32 base_cs, u32 force_unlock) | ||
155 | { | ||
156 | if (!_omap2_sram_ddr_init) | ||
157 | omap_sram_error(); | ||
158 | |||
159 | return _omap2_sram_ddr_init(slow_dll_ctrl, fast_dll_ctrl, | ||
160 | base_cs, force_unlock); | ||
161 | } | ||
162 | |||
163 | static void (*_omap2_sram_reprogram_sdrc)(u32 perf_level, u32 dll_val, | ||
164 | u32 mem_type); | ||
165 | |||
166 | void omap2_sram_reprogram_sdrc(u32 perf_level, u32 dll_val, u32 mem_type) | ||
167 | { | ||
168 | if (!_omap2_sram_reprogram_sdrc) | ||
169 | omap_sram_error(); | ||
170 | |||
171 | return _omap2_sram_reprogram_sdrc(perf_level, dll_val, mem_type); | ||
172 | } | ||
173 | |||
174 | static u32 (*_omap2_set_prcm)(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass); | ||
175 | |||
176 | u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass) | ||
177 | { | ||
178 | if (!_omap2_set_prcm) | ||
179 | omap_sram_error(); | ||
180 | |||
181 | return _omap2_set_prcm(dpll_ctrl_val, sdrc_rfr_val, bypass); | ||
182 | } | ||
183 | |||
184 | int __init omap2_sram_init(void) | ||
185 | { | ||
186 | _omap2_sram_ddr_init = omap_sram_push(sram_ddr_init, sram_ddr_init_sz); | ||
187 | |||
188 | _omap2_sram_reprogram_sdrc = omap_sram_push(sram_reprogram_sdrc, | ||
189 | sram_reprogram_sdrc_sz); | ||
190 | _omap2_set_prcm = omap_sram_push(sram_set_prcm, sram_set_prcm_sz); | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | #else | ||
195 | #define omap2_sram_init() do {} while (0) | ||
196 | #endif | ||
197 | |||
198 | int __init omap_sram_init(void) | ||
199 | { | ||
200 | omap_detect_sram(); | ||
201 | omap_map_sram(); | ||
202 | |||
203 | if (!cpu_is_omap24xx()) | ||
204 | omap1_sram_init(); | ||
205 | else | ||
206 | omap2_sram_init(); | ||
207 | |||
208 | return 0; | ||
120 | } | 209 | } |
diff --git a/arch/arm/plat-omap/sram.h b/arch/arm/plat-omap/sram.h deleted file mode 100644 index 71984efa6ae8..000000000000 --- a/arch/arm/plat-omap/sram.h +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/plat-omap/sram.h | ||
3 | * | ||
4 | * Interface for functions that need to be run in internal SRAM | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #ifndef __ARCH_ARM_OMAP_SRAM_H | ||
12 | #define __ARCH_ARM_OMAP_SRAM_H | ||
13 | |||
14 | extern void * omap_sram_push(void * start, unsigned long size); | ||
15 | extern void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl); | ||
16 | |||
17 | /* Do not use these */ | ||
18 | extern void sram_reprogram_clock(u32 ckctl, u32 dpllctl); | ||
19 | extern unsigned long sram_reprogram_clock_sz; | ||
20 | |||
21 | #endif | ||
diff --git a/arch/arm/plat-omap/usb.c b/arch/arm/plat-omap/usb.c index 205e2d0b826d..00afc7a8c2ab 100644 --- a/arch/arm/plat-omap/usb.c +++ b/arch/arm/plat-omap/usb.c | |||
@@ -91,6 +91,8 @@ EXPORT_SYMBOL(otg_set_transceiver); | |||
91 | 91 | ||
92 | /*-------------------------------------------------------------------------*/ | 92 | /*-------------------------------------------------------------------------*/ |
93 | 93 | ||
94 | #if defined(CONFIG_ARCH_OMAP_OTG) || defined(CONFIG_ARCH_OMAP15XX) | ||
95 | |||
94 | static u32 __init omap_usb0_init(unsigned nwires, unsigned is_device) | 96 | static u32 __init omap_usb0_init(unsigned nwires, unsigned is_device) |
95 | { | 97 | { |
96 | u32 syscon1 = 0; | 98 | u32 syscon1 = 0; |
@@ -271,6 +273,8 @@ static u32 __init omap_usb2_init(unsigned nwires, unsigned alt_pingroup) | |||
271 | return syscon1 << 24; | 273 | return syscon1 << 24; |
272 | } | 274 | } |
273 | 275 | ||
276 | #endif | ||
277 | |||
274 | /*-------------------------------------------------------------------------*/ | 278 | /*-------------------------------------------------------------------------*/ |
275 | 279 | ||
276 | #if defined(CONFIG_USB_GADGET_OMAP) || \ | 280 | #if defined(CONFIG_USB_GADGET_OMAP) || \ |
@@ -494,7 +498,7 @@ static inline void omap_otg_init(struct omap_usb_config *config) {} | |||
494 | 498 | ||
495 | /*-------------------------------------------------------------------------*/ | 499 | /*-------------------------------------------------------------------------*/ |
496 | 500 | ||
497 | #ifdef CONFIG_ARCH_OMAP1510 | 501 | #ifdef CONFIG_ARCH_OMAP15XX |
498 | 502 | ||
499 | #define ULPD_DPLL_CTRL_REG __REG16(ULPD_DPLL_CTRL) | 503 | #define ULPD_DPLL_CTRL_REG __REG16(ULPD_DPLL_CTRL) |
500 | #define DPLL_IOB (1 << 13) | 504 | #define DPLL_IOB (1 << 13) |
@@ -507,7 +511,6 @@ static inline void omap_otg_init(struct omap_usb_config *config) {} | |||
507 | 511 | ||
508 | static void __init omap_1510_usb_init(struct omap_usb_config *config) | 512 | static void __init omap_1510_usb_init(struct omap_usb_config *config) |
509 | { | 513 | { |
510 | int status; | ||
511 | unsigned int val; | 514 | unsigned int val; |
512 | 515 | ||
513 | omap_usb0_init(config->pins[0], is_usb0_device(config)); | 516 | omap_usb0_init(config->pins[0], is_usb0_device(config)); |
@@ -539,6 +542,8 @@ static void __init omap_1510_usb_init(struct omap_usb_config *config) | |||
539 | 542 | ||
540 | #ifdef CONFIG_USB_GADGET_OMAP | 543 | #ifdef CONFIG_USB_GADGET_OMAP |
541 | if (config->register_dev) { | 544 | if (config->register_dev) { |
545 | int status; | ||
546 | |||
542 | udc_device.dev.platform_data = config; | 547 | udc_device.dev.platform_data = config; |
543 | status = platform_device_register(&udc_device); | 548 | status = platform_device_register(&udc_device); |
544 | if (status) | 549 | if (status) |
@@ -549,6 +554,8 @@ static void __init omap_1510_usb_init(struct omap_usb_config *config) | |||
549 | 554 | ||
550 | #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) | 555 | #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) |
551 | if (config->register_host) { | 556 | if (config->register_host) { |
557 | int status; | ||
558 | |||
552 | ohci_device.dev.platform_data = config; | 559 | ohci_device.dev.platform_data = config; |
553 | status = platform_device_register(&ohci_device); | 560 | status = platform_device_register(&ohci_device); |
554 | if (status) | 561 | if (status) |
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 1493c7896fe3..ed31062029f7 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
@@ -599,6 +599,10 @@ config HAVE_ARCH_EARLY_PFN_TO_NID | |||
599 | def_bool y | 599 | def_bool y |
600 | depends on NEED_MULTIPLE_NODES | 600 | depends on NEED_MULTIPLE_NODES |
601 | 601 | ||
602 | config ARCH_MEMORY_PROBE | ||
603 | def_bool y | ||
604 | depends on MEMORY_HOTPLUG | ||
605 | |||
602 | # Some NUMA nodes have memory ranges that span | 606 | # Some NUMA nodes have memory ranges that span |
603 | # other nodes. Even though a pfn is valid and | 607 | # other nodes. Even though a pfn is valid and |
604 | # between a node's start and end pfns, it may not | 608 | # between a node's start and end pfns, it may not |
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index b3ae2993efb8..c04bbd320594 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | ifeq ($(CONFIG_PPC64),y) | 5 | ifeq ($(CONFIG_PPC64),y) |
6 | EXTRA_CFLAGS += -mno-minimal-toc | 6 | EXTRA_CFLAGS += -mno-minimal-toc |
7 | CFLAGS_ioctl32.o += -Ifs/ | ||
7 | endif | 8 | endif |
8 | ifeq ($(CONFIG_PPC32),y) | 9 | ifeq ($(CONFIG_PPC32),y) |
9 | CFLAGS_prom_init.o += -fPIC | 10 | CFLAGS_prom_init.o += -fPIC |
@@ -11,15 +12,21 @@ CFLAGS_btext.o += -fPIC | |||
11 | endif | 12 | endif |
12 | 13 | ||
13 | obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ | 14 | obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ |
14 | signal_32.o pmc.o | 15 | irq.o signal_32.o pmc.o |
15 | obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ | 16 | obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ |
16 | signal_64.o ptrace32.o systbl.o | 17 | signal_64.o ptrace32.o systbl.o \ |
18 | paca.o ioctl32.o cpu_setup_power4.o \ | ||
19 | firmware.o sysfs.o | ||
17 | obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o | 20 | obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o |
18 | obj-$(CONFIG_POWER4) += idle_power4.o | 21 | obj-$(CONFIG_POWER4) += idle_power4.o |
19 | obj-$(CONFIG_PPC_OF) += of_device.o | 22 | obj-$(CONFIG_PPC_OF) += of_device.o |
20 | obj-$(CONFIG_PPC_RTAS) += rtas.o | 23 | procfs-$(CONFIG_PPC64) := proc_ppc64.o |
24 | obj-$(CONFIG_PROC_FS) += $(procfs-y) | ||
25 | rtaspci-$(CONFIG_PPC64) := rtas_pci.o | ||
26 | obj-$(CONFIG_PPC_RTAS) += rtas.o $(rtaspci-y) | ||
21 | obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o | 27 | obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o |
22 | obj-$(CONFIG_RTAS_PROC) += rtas-proc.o | 28 | obj-$(CONFIG_RTAS_PROC) += rtas-proc.o |
29 | obj-$(CONFIG_LPARCFG) += lparcfg.o | ||
23 | obj-$(CONFIG_IBMVIO) += vio.o | 30 | obj-$(CONFIG_IBMVIO) += vio.o |
24 | obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o | 31 | obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o |
25 | 32 | ||
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index b75757251994..8793102711a8 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c | |||
@@ -106,7 +106,6 @@ int main(void) | |||
106 | DEFINE(ICACHEL1LINESIZE, offsetof(struct ppc64_caches, iline_size)); | 106 | DEFINE(ICACHEL1LINESIZE, offsetof(struct ppc64_caches, iline_size)); |
107 | DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_iline_size)); | 107 | DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_iline_size)); |
108 | DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, ilines_per_page)); | 108 | DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, ilines_per_page)); |
109 | DEFINE(PLATFORM, offsetof(struct systemcfg, platform)); | ||
110 | DEFINE(PLATFORM_LPAR, PLATFORM_LPAR); | 109 | DEFINE(PLATFORM_LPAR, PLATFORM_LPAR); |
111 | 110 | ||
112 | /* paca */ | 111 | /* paca */ |
diff --git a/arch/ppc64/kernel/cpu_setup_power4.S b/arch/powerpc/kernel/cpu_setup_power4.S index 1fb673c511ff..cca942fe6115 100644 --- a/arch/ppc64/kernel/cpu_setup_power4.S +++ b/arch/powerpc/kernel/cpu_setup_power4.S | |||
@@ -114,11 +114,11 @@ _GLOBAL(__setup_cpu_ppc970) | |||
114 | 114 | ||
115 | .data | 115 | .data |
116 | .balign L1_CACHE_BYTES,0 | 116 | .balign L1_CACHE_BYTES,0 |
117 | cpu_state_storage: | 117 | cpu_state_storage: |
118 | .space CS_SIZE | 118 | .space CS_SIZE |
119 | .balign L1_CACHE_BYTES,0 | 119 | .balign L1_CACHE_BYTES,0 |
120 | .text | 120 | .text |
121 | 121 | ||
122 | /* Called in normal context to backup CPU 0 state. This | 122 | /* Called in normal context to backup CPU 0 state. This |
123 | * does not include cache settings. This function is also | 123 | * does not include cache settings. This function is also |
124 | * called for machine sleep. This does not include the MMU | 124 | * called for machine sleep. This does not include the MMU |
@@ -151,7 +151,7 @@ _GLOBAL(__save_cpu_setup) | |||
151 | std r3,CS_HID4(r5) | 151 | std r3,CS_HID4(r5) |
152 | mfspr r3,SPRN_HID5 | 152 | mfspr r3,SPRN_HID5 |
153 | std r3,CS_HID5(r5) | 153 | std r3,CS_HID5(r5) |
154 | 154 | ||
155 | 2: | 155 | 2: |
156 | mtcr r7 | 156 | mtcr r7 |
157 | blr | 157 | blr |
@@ -213,7 +213,7 @@ _GLOBAL(__restore_cpu_setup) | |||
213 | mtspr SPRN_HID1,r3 | 213 | mtspr SPRN_HID1,r3 |
214 | sync | 214 | sync |
215 | isync | 215 | isync |
216 | 216 | ||
217 | /* Restore HID4 */ | 217 | /* Restore HID4 */ |
218 | ld r3,CS_HID4(r5) | 218 | ld r3,CS_HID4(r5) |
219 | sync | 219 | sync |
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index cc4e9eb1c13f..1d85cedbbb7b 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c | |||
@@ -52,6 +52,9 @@ extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec); | |||
52 | #define COMMON_USER (PPC_FEATURE_32 | PPC_FEATURE_HAS_FPU | \ | 52 | #define COMMON_USER (PPC_FEATURE_32 | PPC_FEATURE_HAS_FPU | \ |
53 | PPC_FEATURE_HAS_MMU) | 53 | PPC_FEATURE_HAS_MMU) |
54 | #define COMMON_USER_PPC64 (COMMON_USER | PPC_FEATURE_64) | 54 | #define COMMON_USER_PPC64 (COMMON_USER | PPC_FEATURE_64) |
55 | #define COMMON_USER_POWER4 (COMMON_USER_PPC64 | PPC_FEATURE_POWER4) | ||
56 | #define COMMON_USER_POWER5 (COMMON_USER_PPC64 | PPC_FEATURE_POWER5) | ||
57 | #define COMMON_USER_POWER5_PLUS (COMMON_USER_PPC64 | PPC_FEATURE_POWER5_PLUS) | ||
55 | 58 | ||
56 | 59 | ||
57 | /* We only set the spe features if the kernel was compiled with | 60 | /* We only set the spe features if the kernel was compiled with |
@@ -160,7 +163,7 @@ struct cpu_spec cpu_specs[] = { | |||
160 | .pvr_value = 0x00350000, | 163 | .pvr_value = 0x00350000, |
161 | .cpu_name = "POWER4 (gp)", | 164 | .cpu_name = "POWER4 (gp)", |
162 | .cpu_features = CPU_FTRS_POWER4, | 165 | .cpu_features = CPU_FTRS_POWER4, |
163 | .cpu_user_features = COMMON_USER_PPC64, | 166 | .cpu_user_features = COMMON_USER_POWER4, |
164 | .icache_bsize = 128, | 167 | .icache_bsize = 128, |
165 | .dcache_bsize = 128, | 168 | .dcache_bsize = 128, |
166 | .num_pmcs = 8, | 169 | .num_pmcs = 8, |
@@ -175,7 +178,7 @@ struct cpu_spec cpu_specs[] = { | |||
175 | .pvr_value = 0x00380000, | 178 | .pvr_value = 0x00380000, |
176 | .cpu_name = "POWER4+ (gq)", | 179 | .cpu_name = "POWER4+ (gq)", |
177 | .cpu_features = CPU_FTRS_POWER4, | 180 | .cpu_features = CPU_FTRS_POWER4, |
178 | .cpu_user_features = COMMON_USER_PPC64, | 181 | .cpu_user_features = COMMON_USER_POWER4, |
179 | .icache_bsize = 128, | 182 | .icache_bsize = 128, |
180 | .dcache_bsize = 128, | 183 | .dcache_bsize = 128, |
181 | .num_pmcs = 8, | 184 | .num_pmcs = 8, |
@@ -190,7 +193,7 @@ struct cpu_spec cpu_specs[] = { | |||
190 | .pvr_value = 0x00390000, | 193 | .pvr_value = 0x00390000, |
191 | .cpu_name = "PPC970", | 194 | .cpu_name = "PPC970", |
192 | .cpu_features = CPU_FTRS_PPC970, | 195 | .cpu_features = CPU_FTRS_PPC970, |
193 | .cpu_user_features = COMMON_USER_PPC64 | | 196 | .cpu_user_features = COMMON_USER_POWER4 | |
194 | PPC_FEATURE_HAS_ALTIVEC_COMP, | 197 | PPC_FEATURE_HAS_ALTIVEC_COMP, |
195 | .icache_bsize = 128, | 198 | .icache_bsize = 128, |
196 | .dcache_bsize = 128, | 199 | .dcache_bsize = 128, |
@@ -212,7 +215,7 @@ struct cpu_spec cpu_specs[] = { | |||
212 | #else | 215 | #else |
213 | .cpu_features = CPU_FTRS_PPC970, | 216 | .cpu_features = CPU_FTRS_PPC970, |
214 | #endif | 217 | #endif |
215 | .cpu_user_features = COMMON_USER_PPC64 | | 218 | .cpu_user_features = COMMON_USER_POWER4 | |
216 | PPC_FEATURE_HAS_ALTIVEC_COMP, | 219 | PPC_FEATURE_HAS_ALTIVEC_COMP, |
217 | .icache_bsize = 128, | 220 | .icache_bsize = 128, |
218 | .dcache_bsize = 128, | 221 | .dcache_bsize = 128, |
@@ -230,7 +233,7 @@ struct cpu_spec cpu_specs[] = { | |||
230 | .pvr_value = 0x00440000, | 233 | .pvr_value = 0x00440000, |
231 | .cpu_name = "PPC970MP", | 234 | .cpu_name = "PPC970MP", |
232 | .cpu_features = CPU_FTRS_PPC970, | 235 | .cpu_features = CPU_FTRS_PPC970, |
233 | .cpu_user_features = COMMON_USER_PPC64 | | 236 | .cpu_user_features = COMMON_USER_POWER4 | |
234 | PPC_FEATURE_HAS_ALTIVEC_COMP, | 237 | PPC_FEATURE_HAS_ALTIVEC_COMP, |
235 | .icache_bsize = 128, | 238 | .icache_bsize = 128, |
236 | .dcache_bsize = 128, | 239 | .dcache_bsize = 128, |
@@ -245,7 +248,7 @@ struct cpu_spec cpu_specs[] = { | |||
245 | .pvr_value = 0x003a0000, | 248 | .pvr_value = 0x003a0000, |
246 | .cpu_name = "POWER5 (gr)", | 249 | .cpu_name = "POWER5 (gr)", |
247 | .cpu_features = CPU_FTRS_POWER5, | 250 | .cpu_features = CPU_FTRS_POWER5, |
248 | .cpu_user_features = COMMON_USER_PPC64, | 251 | .cpu_user_features = COMMON_USER_POWER5, |
249 | .icache_bsize = 128, | 252 | .icache_bsize = 128, |
250 | .dcache_bsize = 128, | 253 | .dcache_bsize = 128, |
251 | .num_pmcs = 6, | 254 | .num_pmcs = 6, |
@@ -260,7 +263,7 @@ struct cpu_spec cpu_specs[] = { | |||
260 | .pvr_value = 0x003b0000, | 263 | .pvr_value = 0x003b0000, |
261 | .cpu_name = "POWER5 (gs)", | 264 | .cpu_name = "POWER5 (gs)", |
262 | .cpu_features = CPU_FTRS_POWER5, | 265 | .cpu_features = CPU_FTRS_POWER5, |
263 | .cpu_user_features = COMMON_USER_PPC64, | 266 | .cpu_user_features = COMMON_USER_POWER5_PLUS, |
264 | .icache_bsize = 128, | 267 | .icache_bsize = 128, |
265 | .dcache_bsize = 128, | 268 | .dcache_bsize = 128, |
266 | .num_pmcs = 6, | 269 | .num_pmcs = 6, |
@@ -276,7 +279,7 @@ struct cpu_spec cpu_specs[] = { | |||
276 | .cpu_name = "Cell Broadband Engine", | 279 | .cpu_name = "Cell Broadband Engine", |
277 | .cpu_features = CPU_FTRS_CELL, | 280 | .cpu_features = CPU_FTRS_CELL, |
278 | .cpu_user_features = COMMON_USER_PPC64 | | 281 | .cpu_user_features = COMMON_USER_PPC64 | |
279 | PPC_FEATURE_HAS_ALTIVEC_COMP, | 282 | PPC_FEATURE_CELL | PPC_FEATURE_HAS_ALTIVEC_COMP, |
280 | .icache_bsize = 128, | 283 | .icache_bsize = 128, |
281 | .dcache_bsize = 128, | 284 | .dcache_bsize = 128, |
282 | .cpu_setup = __setup_cpu_be, | 285 | .cpu_setup = __setup_cpu_be, |
diff --git a/arch/ppc64/kernel/firmware.c b/arch/powerpc/kernel/firmware.c index d8432c0fb27d..65eae752a527 100644 --- a/arch/ppc64/kernel/firmware.c +++ b/arch/powerpc/kernel/firmware.c | |||
@@ -1,6 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * arch/ppc64/kernel/firmware.c | ||
3 | * | ||
4 | * Extracted from cputable.c | 2 | * Extracted from cputable.c |
5 | * | 3 | * |
6 | * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org) | 4 | * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org) |
diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S index 4d6001fa1cf2..b780b42c95fc 100644 --- a/arch/powerpc/kernel/fpu.S +++ b/arch/powerpc/kernel/fpu.S | |||
@@ -41,20 +41,20 @@ _GLOBAL(load_up_fpu) | |||
41 | #ifndef CONFIG_SMP | 41 | #ifndef CONFIG_SMP |
42 | LOADBASE(r3, last_task_used_math) | 42 | LOADBASE(r3, last_task_used_math) |
43 | toreal(r3) | 43 | toreal(r3) |
44 | LDL r4,OFF(last_task_used_math)(r3) | 44 | PPC_LL r4,OFF(last_task_used_math)(r3) |
45 | CMPI 0,r4,0 | 45 | PPC_LCMPI 0,r4,0 |
46 | beq 1f | 46 | beq 1f |
47 | toreal(r4) | 47 | toreal(r4) |
48 | addi r4,r4,THREAD /* want last_task_used_math->thread */ | 48 | addi r4,r4,THREAD /* want last_task_used_math->thread */ |
49 | SAVE_32FPRS(0, r4) | 49 | SAVE_32FPRS(0, r4) |
50 | mffs fr0 | 50 | mffs fr0 |
51 | stfd fr0,THREAD_FPSCR(r4) | 51 | stfd fr0,THREAD_FPSCR(r4) |
52 | LDL r5,PT_REGS(r4) | 52 | PPC_LL r5,PT_REGS(r4) |
53 | toreal(r5) | 53 | toreal(r5) |
54 | LDL r4,_MSR-STACK_FRAME_OVERHEAD(r5) | 54 | PPC_LL r4,_MSR-STACK_FRAME_OVERHEAD(r5) |
55 | li r10,MSR_FP|MSR_FE0|MSR_FE1 | 55 | li r10,MSR_FP|MSR_FE0|MSR_FE1 |
56 | andc r4,r4,r10 /* disable FP for previous task */ | 56 | andc r4,r4,r10 /* disable FP for previous task */ |
57 | STL r4,_MSR-STACK_FRAME_OVERHEAD(r5) | 57 | PPC_STL r4,_MSR-STACK_FRAME_OVERHEAD(r5) |
58 | 1: | 58 | 1: |
59 | #endif /* CONFIG_SMP */ | 59 | #endif /* CONFIG_SMP */ |
60 | /* enable use of FP after return */ | 60 | /* enable use of FP after return */ |
@@ -77,7 +77,7 @@ _GLOBAL(load_up_fpu) | |||
77 | #ifndef CONFIG_SMP | 77 | #ifndef CONFIG_SMP |
78 | subi r4,r5,THREAD | 78 | subi r4,r5,THREAD |
79 | fromreal(r4) | 79 | fromreal(r4) |
80 | STL r4,OFF(last_task_used_math)(r3) | 80 | PPC_STL r4,OFF(last_task_used_math)(r3) |
81 | #endif /* CONFIG_SMP */ | 81 | #endif /* CONFIG_SMP */ |
82 | /* restore registers and return */ | 82 | /* restore registers and return */ |
83 | /* we haven't used ctr or xer or lr */ | 83 | /* we haven't used ctr or xer or lr */ |
@@ -97,24 +97,24 @@ _GLOBAL(giveup_fpu) | |||
97 | MTMSRD(r5) /* enable use of fpu now */ | 97 | MTMSRD(r5) /* enable use of fpu now */ |
98 | SYNC_601 | 98 | SYNC_601 |
99 | isync | 99 | isync |
100 | CMPI 0,r3,0 | 100 | PPC_LCMPI 0,r3,0 |
101 | beqlr- /* if no previous owner, done */ | 101 | beqlr- /* if no previous owner, done */ |
102 | addi r3,r3,THREAD /* want THREAD of task */ | 102 | addi r3,r3,THREAD /* want THREAD of task */ |
103 | LDL r5,PT_REGS(r3) | 103 | PPC_LL r5,PT_REGS(r3) |
104 | CMPI 0,r5,0 | 104 | PPC_LCMPI 0,r5,0 |
105 | SAVE_32FPRS(0, r3) | 105 | SAVE_32FPRS(0, r3) |
106 | mffs fr0 | 106 | mffs fr0 |
107 | stfd fr0,THREAD_FPSCR(r3) | 107 | stfd fr0,THREAD_FPSCR(r3) |
108 | beq 1f | 108 | beq 1f |
109 | LDL r4,_MSR-STACK_FRAME_OVERHEAD(r5) | 109 | PPC_LL r4,_MSR-STACK_FRAME_OVERHEAD(r5) |
110 | li r3,MSR_FP|MSR_FE0|MSR_FE1 | 110 | li r3,MSR_FP|MSR_FE0|MSR_FE1 |
111 | andc r4,r4,r3 /* disable FP for previous task */ | 111 | andc r4,r4,r3 /* disable FP for previous task */ |
112 | STL r4,_MSR-STACK_FRAME_OVERHEAD(r5) | 112 | PPC_STL r4,_MSR-STACK_FRAME_OVERHEAD(r5) |
113 | 1: | 113 | 1: |
114 | #ifndef CONFIG_SMP | 114 | #ifndef CONFIG_SMP |
115 | li r5,0 | 115 | li r5,0 |
116 | LOADBASE(r4,last_task_used_math) | 116 | LOADBASE(r4,last_task_used_math) |
117 | STL r5,OFF(last_task_used_math)(r4) | 117 | PPC_STL r5,OFF(last_task_used_math)(r4) |
118 | #endif /* CONFIG_SMP */ | 118 | #endif /* CONFIG_SMP */ |
119 | blr | 119 | blr |
120 | 120 | ||
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 16ab40daa738..8a8bf79ef044 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S | |||
@@ -28,7 +28,6 @@ | |||
28 | #include <asm/reg.h> | 28 | #include <asm/reg.h> |
29 | #include <asm/page.h> | 29 | #include <asm/page.h> |
30 | #include <asm/mmu.h> | 30 | #include <asm/mmu.h> |
31 | #include <asm/systemcfg.h> | ||
32 | #include <asm/ppc_asm.h> | 31 | #include <asm/ppc_asm.h> |
33 | #include <asm/asm-offsets.h> | 32 | #include <asm/asm-offsets.h> |
34 | #include <asm/bug.h> | 33 | #include <asm/bug.h> |
@@ -1697,25 +1696,14 @@ _GLOBAL(pmac_secondary_start) | |||
1697 | * SPRG3 = paca virtual address | 1696 | * SPRG3 = paca virtual address |
1698 | */ | 1697 | */ |
1699 | _GLOBAL(__secondary_start) | 1698 | _GLOBAL(__secondary_start) |
1699 | /* Set thread priority to MEDIUM */ | ||
1700 | HMT_MEDIUM | ||
1700 | 1701 | ||
1701 | HMT_MEDIUM /* Set thread priority to MEDIUM */ | 1702 | /* Load TOC */ |
1702 | |||
1703 | ld r2,PACATOC(r13) | 1703 | ld r2,PACATOC(r13) |
1704 | li r6,0 | 1704 | |
1705 | stb r6,PACAPROCENABLED(r13) | 1705 | /* Do early setup for that CPU (stab, slb, hash table pointer) */ |
1706 | 1706 | bl .early_setup_secondary | |
1707 | #ifndef CONFIG_PPC_ISERIES | ||
1708 | /* Initialize the page table pointer register. */ | ||
1709 | LOADADDR(r6,_SDR1) | ||
1710 | ld r6,0(r6) /* get the value of _SDR1 */ | ||
1711 | mtspr SPRN_SDR1,r6 /* set the htab location */ | ||
1712 | #endif | ||
1713 | /* Initialize the first segment table (or SLB) entry */ | ||
1714 | ld r3,PACASTABVIRT(r13) /* get addr of segment table */ | ||
1715 | BEGIN_FTR_SECTION | ||
1716 | bl .stab_initialize | ||
1717 | END_FTR_SECTION_IFCLR(CPU_FTR_SLB) | ||
1718 | bl .slb_initialize | ||
1719 | 1707 | ||
1720 | /* Initialize the kernel stack. Just a repeat for iSeries. */ | 1708 | /* Initialize the kernel stack. Just a repeat for iSeries. */ |
1721 | LOADADDR(r3,current_set) | 1709 | LOADADDR(r3,current_set) |
@@ -1724,37 +1712,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB) | |||
1724 | addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD | 1712 | addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD |
1725 | std r1,PACAKSAVE(r13) | 1713 | std r1,PACAKSAVE(r13) |
1726 | 1714 | ||
1727 | ld r3,PACASTABREAL(r13) /* get raddr of segment table */ | 1715 | /* Clear backchain so we get nice backtraces */ |
1728 | ori r4,r3,1 /* turn on valid bit */ | ||
1729 | |||
1730 | #ifdef CONFIG_PPC_ISERIES | ||
1731 | li r0,-1 /* hypervisor call */ | ||
1732 | li r3,1 | ||
1733 | sldi r3,r3,63 /* 0x8000000000000000 */ | ||
1734 | ori r3,r3,4 /* 0x8000000000000004 */ | ||
1735 | sc /* HvCall_setASR */ | ||
1736 | #else | ||
1737 | /* set the ASR */ | ||
1738 | ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */ | ||
1739 | ld r3,0(r3) | ||
1740 | lwz r3,PLATFORM(r3) /* r3 = platform flags */ | ||
1741 | andi. r3,r3,PLATFORM_LPAR /* Test if bit 0 is set (LPAR bit) */ | ||
1742 | beq 98f /* branch if result is 0 */ | ||
1743 | mfspr r3,SPRN_PVR | ||
1744 | srwi r3,r3,16 | ||
1745 | cmpwi r3,0x37 /* SStar */ | ||
1746 | beq 97f | ||
1747 | cmpwi r3,0x36 /* IStar */ | ||
1748 | beq 97f | ||
1749 | cmpwi r3,0x34 /* Pulsar */ | ||
1750 | bne 98f | ||
1751 | 97: li r3,H_SET_ASR /* hcall = H_SET_ASR */ | ||
1752 | HVSC /* Invoking hcall */ | ||
1753 | b 99f | ||
1754 | 98: /* !(rpa hypervisor) || !(star) */ | ||
1755 | mtasr r4 /* set the stab location */ | ||
1756 | 99: | ||
1757 | #endif | ||
1758 | li r7,0 | 1716 | li r7,0 |
1759 | mtlr r7 | 1717 | mtlr r7 |
1760 | 1718 | ||
@@ -1777,6 +1735,7 @@ _GLOBAL(start_secondary_prolog) | |||
1777 | li r3,0 | 1735 | li r3,0 |
1778 | std r3,0(r1) /* Zero the stack frame pointer */ | 1736 | std r3,0(r1) /* Zero the stack frame pointer */ |
1779 | bl .start_secondary | 1737 | bl .start_secondary |
1738 | b . | ||
1780 | #endif | 1739 | #endif |
1781 | 1740 | ||
1782 | /* | 1741 | /* |
@@ -1896,40 +1855,6 @@ _STATIC(start_here_multiplatform) | |||
1896 | mr r3,r31 | 1855 | mr r3,r31 |
1897 | bl .early_setup | 1856 | bl .early_setup |
1898 | 1857 | ||
1899 | /* set the ASR */ | ||
1900 | ld r3,PACASTABREAL(r13) | ||
1901 | ori r4,r3,1 /* turn on valid bit */ | ||
1902 | ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */ | ||
1903 | ld r3,0(r3) | ||
1904 | lwz r3,PLATFORM(r3) /* r3 = platform flags */ | ||
1905 | andi. r3,r3,PLATFORM_LPAR /* Test if bit 0 is set (LPAR bit) */ | ||
1906 | beq 98f /* branch if result is 0 */ | ||
1907 | mfspr r3,SPRN_PVR | ||
1908 | srwi r3,r3,16 | ||
1909 | cmpwi r3,0x37 /* SStar */ | ||
1910 | beq 97f | ||
1911 | cmpwi r3,0x36 /* IStar */ | ||
1912 | beq 97f | ||
1913 | cmpwi r3,0x34 /* Pulsar */ | ||
1914 | bne 98f | ||
1915 | 97: li r3,H_SET_ASR /* hcall = H_SET_ASR */ | ||
1916 | HVSC /* Invoking hcall */ | ||
1917 | b 99f | ||
1918 | 98: /* !(rpa hypervisor) || !(star) */ | ||
1919 | mtasr r4 /* set the stab location */ | ||
1920 | 99: | ||
1921 | /* Set SDR1 (hash table pointer) */ | ||
1922 | ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */ | ||
1923 | ld r3,0(r3) | ||
1924 | lwz r3,PLATFORM(r3) /* r3 = platform flags */ | ||
1925 | /* Test if bit 0 is set (LPAR bit) */ | ||
1926 | andi. r3,r3,PLATFORM_LPAR | ||
1927 | bne 98f /* branch if result is !0 */ | ||
1928 | LOADADDR(r6,_SDR1) /* Only if NOT LPAR */ | ||
1929 | add r6,r6,r26 | ||
1930 | ld r6,0(r6) /* get the value of _SDR1 */ | ||
1931 | mtspr SPRN_SDR1,r6 /* set the htab location */ | ||
1932 | 98: | ||
1933 | LOADADDR(r3,.start_here_common) | 1858 | LOADADDR(r3,.start_here_common) |
1934 | SET_REG_TO_CONST(r4, MSR_KERNEL) | 1859 | SET_REG_TO_CONST(r4, MSR_KERNEL) |
1935 | mtspr SPRN_SRR0,r3 | 1860 | mtspr SPRN_SRR0,r3 |
diff --git a/arch/ppc64/kernel/ioctl32.c b/arch/powerpc/kernel/ioctl32.c index ba4a899045c2..3fa6a93adbd0 100644 --- a/arch/ppc64/kernel/ioctl32.c +++ b/arch/powerpc/kernel/ioctl32.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * ioctl32.c: Conversion between 32bit and 64bit native ioctls. | 2 | * ioctl32.c: Conversion between 32bit and 64bit native ioctls. |
3 | * | 3 | * |
4 | * Based on sparc64 ioctl32.c by: | 4 | * Based on sparc64 ioctl32.c by: |
5 | * | 5 | * |
6 | * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) | 6 | * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) |
diff --git a/arch/ppc64/kernel/irq.c b/arch/powerpc/kernel/irq.c index 87474584033f..4b7940693f3d 100644 --- a/arch/ppc64/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c | |||
@@ -5,12 +5,12 @@ | |||
5 | * Copyright (C) 1992 Linus Torvalds | 5 | * Copyright (C) 1992 Linus Torvalds |
6 | * Adapted from arch/i386 by Gary Thomas | 6 | * Adapted from arch/i386 by Gary Thomas |
7 | * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) | 7 | * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) |
8 | * Updated and modified by Cort Dougan (cort@cs.nmt.edu) | 8 | * Updated and modified by Cort Dougan <cort@fsmlabs.com> |
9 | * Copyright (C) 1996 Cort Dougan | 9 | * Copyright (C) 1996-2001 Cort Dougan |
10 | * Adapted for Power Macintosh by Paul Mackerras | 10 | * Adapted for Power Macintosh by Paul Mackerras |
11 | * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) | 11 | * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) |
12 | * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). | 12 | * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). |
13 | * | 13 | * |
14 | * This program is free software; you can redistribute it and/or | 14 | * This program is free software; you can redistribute it and/or |
15 | * modify it under the terms of the GNU General Public License | 15 | * modify it under the terms of the GNU General Public License |
16 | * as published by the Free Software Foundation; either version | 16 | * as published by the Free Software Foundation; either version |
@@ -21,6 +21,14 @@ | |||
21 | * instead of just grabbing them. Thus setups with different IRQ numbers | 21 | * instead of just grabbing them. Thus setups with different IRQ numbers |
22 | * shouldn't result in any weird surprises, and installing new handlers | 22 | * shouldn't result in any weird surprises, and installing new handlers |
23 | * should be easier. | 23 | * should be easier. |
24 | * | ||
25 | * The MPC8xx has an interrupt mask in the SIU. If a bit is set, the | ||
26 | * interrupt is _enabled_. As expected, IRQ0 is bit 0 in the 32-bit | ||
27 | * mask register (of which only 16 are defined), hence the weird shifting | ||
28 | * and complement of the cached_irq_mask. I want to be able to stuff | ||
29 | * this right into the SIU SMASK register. | ||
30 | * Many of the prep/chrp functions are conditional compiled on CONFIG_8xx | ||
31 | * to reduce code space and undefined function references. | ||
24 | */ | 32 | */ |
25 | 33 | ||
26 | #include <linux/errno.h> | 34 | #include <linux/errno.h> |
@@ -29,6 +37,7 @@ | |||
29 | #include <linux/kernel_stat.h> | 37 | #include <linux/kernel_stat.h> |
30 | #include <linux/signal.h> | 38 | #include <linux/signal.h> |
31 | #include <linux/sched.h> | 39 | #include <linux/sched.h> |
40 | #include <linux/ptrace.h> | ||
32 | #include <linux/ioport.h> | 41 | #include <linux/ioport.h> |
33 | #include <linux/interrupt.h> | 42 | #include <linux/interrupt.h> |
34 | #include <linux/timex.h> | 43 | #include <linux/timex.h> |
@@ -40,9 +49,13 @@ | |||
40 | #include <linux/irq.h> | 49 | #include <linux/irq.h> |
41 | #include <linux/proc_fs.h> | 50 | #include <linux/proc_fs.h> |
42 | #include <linux/random.h> | 51 | #include <linux/random.h> |
43 | #include <linux/kallsyms.h> | 52 | #include <linux/seq_file.h> |
53 | #include <linux/cpumask.h> | ||
44 | #include <linux/profile.h> | 54 | #include <linux/profile.h> |
45 | #include <linux/bitops.h> | 55 | #include <linux/bitops.h> |
56 | #ifdef CONFIG_PPC64 | ||
57 | #include <linux/kallsyms.h> | ||
58 | #endif | ||
46 | 59 | ||
47 | #include <asm/uaccess.h> | 60 | #include <asm/uaccess.h> |
48 | #include <asm/system.h> | 61 | #include <asm/system.h> |
@@ -52,35 +65,54 @@ | |||
52 | #include <asm/cache.h> | 65 | #include <asm/cache.h> |
53 | #include <asm/prom.h> | 66 | #include <asm/prom.h> |
54 | #include <asm/ptrace.h> | 67 | #include <asm/ptrace.h> |
55 | #include <asm/iseries/it_lp_queue.h> | ||
56 | #include <asm/machdep.h> | 68 | #include <asm/machdep.h> |
69 | #ifdef CONFIG_PPC64 | ||
70 | #include <asm/iseries/it_lp_queue.h> | ||
57 | #include <asm/paca.h> | 71 | #include <asm/paca.h> |
72 | #endif | ||
58 | 73 | ||
59 | #ifdef CONFIG_SMP | 74 | static int ppc_spurious_interrupts; |
60 | extern void iSeries_smp_message_recv( struct pt_regs * ); | 75 | |
76 | #if defined(CONFIG_PPC_ISERIES) && defined(CONFIG_SMP) | ||
77 | extern void iSeries_smp_message_recv(struct pt_regs *); | ||
78 | #endif | ||
79 | |||
80 | #ifdef CONFIG_PPC32 | ||
81 | #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) | ||
82 | |||
83 | unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; | ||
84 | atomic_t ppc_n_lost_interrupts; | ||
85 | |||
86 | #ifdef CONFIG_TAU_INT | ||
87 | extern int tau_initialized; | ||
88 | extern int tau_interrupts(int); | ||
89 | #endif | ||
90 | |||
91 | #if defined(CONFIG_SMP) && !defined(CONFIG_PPC_MERGE) | ||
92 | extern atomic_t ipi_recv; | ||
93 | extern atomic_t ipi_sent; | ||
61 | #endif | 94 | #endif |
95 | #endif /* CONFIG_PPC32 */ | ||
62 | 96 | ||
63 | extern irq_desc_t irq_desc[NR_IRQS]; | 97 | #ifdef CONFIG_PPC64 |
64 | EXPORT_SYMBOL(irq_desc); | 98 | EXPORT_SYMBOL(irq_desc); |
65 | 99 | ||
66 | int distribute_irqs = 1; | 100 | int distribute_irqs = 1; |
67 | int __irq_offset_value; | 101 | int __irq_offset_value; |
68 | int ppc_spurious_interrupts; | ||
69 | u64 ppc64_interrupt_controller; | 102 | u64 ppc64_interrupt_controller; |
103 | #endif /* CONFIG_PPC64 */ | ||
70 | 104 | ||
71 | int show_interrupts(struct seq_file *p, void *v) | 105 | int show_interrupts(struct seq_file *p, void *v) |
72 | { | 106 | { |
73 | int i = *(loff_t *) v, j; | 107 | int i = *(loff_t *)v, j; |
74 | struct irqaction * action; | 108 | struct irqaction *action; |
75 | irq_desc_t *desc; | 109 | irq_desc_t *desc; |
76 | unsigned long flags; | 110 | unsigned long flags; |
77 | 111 | ||
78 | if (i == 0) { | 112 | if (i == 0) { |
79 | seq_printf(p, " "); | 113 | seq_puts(p, " "); |
80 | for (j=0; j<NR_CPUS; j++) { | 114 | for_each_online_cpu(j) |
81 | if (cpu_online(j)) | 115 | seq_printf(p, "CPU%d ", j); |
82 | seq_printf(p, "CPU%d ",j); | ||
83 | } | ||
84 | seq_putc(p, '\n'); | 116 | seq_putc(p, '\n'); |
85 | } | 117 | } |
86 | 118 | ||
@@ -92,26 +124,41 @@ int show_interrupts(struct seq_file *p, void *v) | |||
92 | goto skip; | 124 | goto skip; |
93 | seq_printf(p, "%3d: ", i); | 125 | seq_printf(p, "%3d: ", i); |
94 | #ifdef CONFIG_SMP | 126 | #ifdef CONFIG_SMP |
95 | for (j = 0; j < NR_CPUS; j++) { | 127 | for_each_online_cpu(j) |
96 | if (cpu_online(j)) | 128 | seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); |
97 | seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); | ||
98 | } | ||
99 | #else | 129 | #else |
100 | seq_printf(p, "%10u ", kstat_irqs(i)); | 130 | seq_printf(p, "%10u ", kstat_irqs(i)); |
101 | #endif /* CONFIG_SMP */ | 131 | #endif /* CONFIG_SMP */ |
102 | if (desc->handler) | 132 | if (desc->handler) |
103 | seq_printf(p, " %s ", desc->handler->typename ); | 133 | seq_printf(p, " %s ", desc->handler->typename); |
104 | else | 134 | else |
105 | seq_printf(p, " None "); | 135 | seq_puts(p, " None "); |
106 | seq_printf(p, "%s", (desc->status & IRQ_LEVEL) ? "Level " : "Edge "); | 136 | seq_printf(p, "%s", (desc->status & IRQ_LEVEL) ? "Level " : "Edge "); |
107 | seq_printf(p, " %s",action->name); | 137 | seq_printf(p, " %s", action->name); |
108 | for (action=action->next; action; action = action->next) | 138 | for (action = action->next; action; action = action->next) |
109 | seq_printf(p, ", %s", action->name); | 139 | seq_printf(p, ", %s", action->name); |
110 | seq_putc(p, '\n'); | 140 | seq_putc(p, '\n'); |
111 | skip: | 141 | skip: |
112 | spin_unlock_irqrestore(&desc->lock, flags); | 142 | spin_unlock_irqrestore(&desc->lock, flags); |
113 | } else if (i == NR_IRQS) | 143 | } else if (i == NR_IRQS) { |
144 | #ifdef CONFIG_PPC32 | ||
145 | #ifdef CONFIG_TAU_INT | ||
146 | if (tau_initialized){ | ||
147 | seq_puts(p, "TAU: "); | ||
148 | for (j = 0; j < NR_CPUS; j++) | ||
149 | if (cpu_online(j)) | ||
150 | seq_printf(p, "%10u ", tau_interrupts(j)); | ||
151 | seq_puts(p, " PowerPC Thermal Assist (cpu temp)\n"); | ||
152 | } | ||
153 | #endif | ||
154 | #if defined(CONFIG_SMP) && !defined(CONFIG_PPC_MERGE) | ||
155 | /* should this be per processor send/receive? */ | ||
156 | seq_printf(p, "IPI (recv/sent): %10u/%u\n", | ||
157 | atomic_read(&ipi_recv), atomic_read(&ipi_sent)); | ||
158 | #endif | ||
159 | #endif /* CONFIG_PPC32 */ | ||
114 | seq_printf(p, "BAD: %10u\n", ppc_spurious_interrupts); | 160 | seq_printf(p, "BAD: %10u\n", ppc_spurious_interrupts); |
161 | } | ||
115 | return 0; | 162 | return 0; |
116 | } | 163 | } |
117 | 164 | ||
@@ -144,126 +191,6 @@ void fixup_irqs(cpumask_t map) | |||
144 | } | 191 | } |
145 | #endif | 192 | #endif |
146 | 193 | ||
147 | extern int noirqdebug; | ||
148 | |||
149 | /* | ||
150 | * Eventually, this should take an array of interrupts and an array size | ||
151 | * so it can dispatch multiple interrupts. | ||
152 | */ | ||
153 | void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq) | ||
154 | { | ||
155 | int status; | ||
156 | struct irqaction *action; | ||
157 | int cpu = smp_processor_id(); | ||
158 | irq_desc_t *desc = get_irq_desc(irq); | ||
159 | irqreturn_t action_ret; | ||
160 | #ifdef CONFIG_IRQSTACKS | ||
161 | struct thread_info *curtp, *irqtp; | ||
162 | #endif | ||
163 | |||
164 | kstat_cpu(cpu).irqs[irq]++; | ||
165 | |||
166 | if (desc->status & IRQ_PER_CPU) { | ||
167 | /* no locking required for CPU-local interrupts: */ | ||
168 | ack_irq(irq); | ||
169 | action_ret = handle_IRQ_event(irq, regs, desc->action); | ||
170 | desc->handler->end(irq); | ||
171 | return; | ||
172 | } | ||
173 | |||
174 | spin_lock(&desc->lock); | ||
175 | ack_irq(irq); | ||
176 | /* | ||
177 | REPLAY is when Linux resends an IRQ that was dropped earlier | ||
178 | WAITING is used by probe to mark irqs that are being tested | ||
179 | */ | ||
180 | status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); | ||
181 | status |= IRQ_PENDING; /* we _want_ to handle it */ | ||
182 | |||
183 | /* | ||
184 | * If the IRQ is disabled for whatever reason, we cannot | ||
185 | * use the action we have. | ||
186 | */ | ||
187 | action = NULL; | ||
188 | if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) { | ||
189 | action = desc->action; | ||
190 | if (!action || !action->handler) { | ||
191 | ppc_spurious_interrupts++; | ||
192 | printk(KERN_DEBUG "Unhandled interrupt %x, disabled\n", irq); | ||
193 | /* We can't call disable_irq here, it would deadlock */ | ||
194 | if (!desc->depth) | ||
195 | desc->depth = 1; | ||
196 | desc->status |= IRQ_DISABLED; | ||
197 | /* This is not a real spurrious interrupt, we | ||
198 | * have to eoi it, so we jump to out | ||
199 | */ | ||
200 | mask_irq(irq); | ||
201 | goto out; | ||
202 | } | ||
203 | status &= ~IRQ_PENDING; /* we commit to handling */ | ||
204 | status |= IRQ_INPROGRESS; /* we are handling it */ | ||
205 | } | ||
206 | desc->status = status; | ||
207 | |||
208 | /* | ||
209 | * If there is no IRQ handler or it was disabled, exit early. | ||
210 | Since we set PENDING, if another processor is handling | ||
211 | a different instance of this same irq, the other processor | ||
212 | will take care of it. | ||
213 | */ | ||
214 | if (unlikely(!action)) | ||
215 | goto out; | ||
216 | |||
217 | /* | ||
218 | * Edge triggered interrupts need to remember | ||
219 | * pending events. | ||
220 | * This applies to any hw interrupts that allow a second | ||
221 | * instance of the same irq to arrive while we are in do_IRQ | ||
222 | * or in the handler. But the code here only handles the _second_ | ||
223 | * instance of the irq, not the third or fourth. So it is mostly | ||
224 | * useful for irq hardware that does not mask cleanly in an | ||
225 | * SMP environment. | ||
226 | */ | ||
227 | for (;;) { | ||
228 | spin_unlock(&desc->lock); | ||
229 | |||
230 | #ifdef CONFIG_IRQSTACKS | ||
231 | /* Switch to the irq stack to handle this */ | ||
232 | curtp = current_thread_info(); | ||
233 | irqtp = hardirq_ctx[smp_processor_id()]; | ||
234 | if (curtp != irqtp) { | ||
235 | irqtp->task = curtp->task; | ||
236 | irqtp->flags = 0; | ||
237 | action_ret = call_handle_IRQ_event(irq, regs, action, irqtp); | ||
238 | irqtp->task = NULL; | ||
239 | if (irqtp->flags) | ||
240 | set_bits(irqtp->flags, &curtp->flags); | ||
241 | } else | ||
242 | #endif | ||
243 | action_ret = handle_IRQ_event(irq, regs, action); | ||
244 | |||
245 | spin_lock(&desc->lock); | ||
246 | if (!noirqdebug) | ||
247 | note_interrupt(irq, desc, action_ret, regs); | ||
248 | if (likely(!(desc->status & IRQ_PENDING))) | ||
249 | break; | ||
250 | desc->status &= ~IRQ_PENDING; | ||
251 | } | ||
252 | out: | ||
253 | desc->status &= ~IRQ_INPROGRESS; | ||
254 | /* | ||
255 | * The ->end() handler has to deal with interrupts which got | ||
256 | * disabled while the handler was running. | ||
257 | */ | ||
258 | if (desc->handler) { | ||
259 | if (desc->handler->end) | ||
260 | desc->handler->end(irq); | ||
261 | else if (desc->handler->enable) | ||
262 | desc->handler->enable(irq); | ||
263 | } | ||
264 | spin_unlock(&desc->lock); | ||
265 | } | ||
266 | |||
267 | #ifdef CONFIG_PPC_ISERIES | 194 | #ifdef CONFIG_PPC_ISERIES |
268 | void do_IRQ(struct pt_regs *regs) | 195 | void do_IRQ(struct pt_regs *regs) |
269 | { | 196 | { |
@@ -310,8 +237,11 @@ void do_IRQ(struct pt_regs *regs) | |||
310 | void do_IRQ(struct pt_regs *regs) | 237 | void do_IRQ(struct pt_regs *regs) |
311 | { | 238 | { |
312 | int irq; | 239 | int irq; |
240 | #ifdef CONFIG_IRQSTACKS | ||
241 | struct thread_info *curtp, *irqtp; | ||
242 | #endif | ||
313 | 243 | ||
314 | irq_enter(); | 244 | irq_enter(); |
315 | 245 | ||
316 | #ifdef CONFIG_DEBUG_STACKOVERFLOW | 246 | #ifdef CONFIG_DEBUG_STACKOVERFLOW |
317 | /* Debugging check for stack overflow: is there less than 2KB free? */ | 247 | /* Debugging check for stack overflow: is there less than 2KB free? */ |
@@ -328,20 +258,44 @@ void do_IRQ(struct pt_regs *regs) | |||
328 | } | 258 | } |
329 | #endif | 259 | #endif |
330 | 260 | ||
261 | /* | ||
262 | * Every platform is required to implement ppc_md.get_irq. | ||
263 | * This function will either return an irq number or -1 to | ||
264 | * indicate there are no more pending. | ||
265 | * The value -2 is for buggy hardware and means that this IRQ | ||
266 | * has already been handled. -- Tom | ||
267 | */ | ||
331 | irq = ppc_md.get_irq(regs); | 268 | irq = ppc_md.get_irq(regs); |
332 | 269 | ||
333 | if (irq >= 0) | 270 | if (irq >= 0) { |
334 | ppc_irq_dispatch_handler(regs, irq); | 271 | #ifdef CONFIG_IRQSTACKS |
335 | else | 272 | /* Switch to the irq stack to handle this */ |
336 | /* That's not SMP safe ... but who cares ? */ | 273 | curtp = current_thread_info(); |
337 | ppc_spurious_interrupts++; | 274 | irqtp = hardirq_ctx[smp_processor_id()]; |
338 | 275 | if (curtp != irqtp) { | |
339 | irq_exit(); | 276 | irqtp->task = curtp->task; |
277 | irqtp->flags = 0; | ||
278 | call___do_IRQ(irq, regs, irqtp); | ||
279 | irqtp->task = NULL; | ||
280 | if (irqtp->flags) | ||
281 | set_bits(irqtp->flags, &curtp->flags); | ||
282 | } else | ||
283 | #endif | ||
284 | __do_IRQ(irq, regs); | ||
285 | } else | ||
286 | #ifdef CONFIG_PPC32 | ||
287 | if (irq != -2) | ||
288 | #endif | ||
289 | /* That's not SMP safe ... but who cares ? */ | ||
290 | ppc_spurious_interrupts++; | ||
291 | irq_exit(); | ||
340 | } | 292 | } |
293 | |||
341 | #endif /* CONFIG_PPC_ISERIES */ | 294 | #endif /* CONFIG_PPC_ISERIES */ |
342 | 295 | ||
343 | void __init init_IRQ(void) | 296 | void __init init_IRQ(void) |
344 | { | 297 | { |
298 | #ifdef CONFIG_PPC64 | ||
345 | static int once = 0; | 299 | static int once = 0; |
346 | 300 | ||
347 | if (once) | 301 | if (once) |
@@ -349,10 +303,14 @@ void __init init_IRQ(void) | |||
349 | 303 | ||
350 | once++; | 304 | once++; |
351 | 305 | ||
306 | #endif | ||
352 | ppc_md.init_IRQ(); | 307 | ppc_md.init_IRQ(); |
308 | #ifdef CONFIG_PPC64 | ||
353 | irq_ctx_init(); | 309 | irq_ctx_init(); |
310 | #endif | ||
354 | } | 311 | } |
355 | 312 | ||
313 | #ifdef CONFIG_PPC64 | ||
356 | #ifndef CONFIG_PPC_ISERIES | 314 | #ifndef CONFIG_PPC_ISERIES |
357 | /* | 315 | /* |
358 | * Virtual IRQ mapping code, used on systems with XICS interrupt controllers. | 316 | * Virtual IRQ mapping code, used on systems with XICS interrupt controllers. |
@@ -517,3 +475,4 @@ static int __init setup_noirqdistrib(char *str) | |||
517 | } | 475 | } |
518 | 476 | ||
519 | __setup("noirqdistrib", setup_noirqdistrib); | 477 | __setup("noirqdistrib", setup_noirqdistrib); |
478 | #endif /* CONFIG_PPC64 */ | ||
diff --git a/arch/ppc64/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c index 3e7b2f28ec83..5e954fae031f 100644 --- a/arch/ppc64/kernel/lparcfg.c +++ b/arch/powerpc/kernel/lparcfg.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <asm/time.h> | 35 | #include <asm/time.h> |
36 | #include <asm/iseries/it_exp_vpd_panel.h> | 36 | #include <asm/iseries/it_exp_vpd_panel.h> |
37 | #include <asm/prom.h> | 37 | #include <asm/prom.h> |
38 | #include <asm/systemcfg.h> | ||
38 | 39 | ||
39 | #define MODULE_VERS "1.6" | 40 | #define MODULE_VERS "1.6" |
40 | #define MODULE_NAME "lparcfg" | 41 | #define MODULE_NAME "lparcfg" |
@@ -96,7 +97,7 @@ static unsigned long get_purr(void) | |||
96 | 97 | ||
97 | #define lparcfg_write NULL | 98 | #define lparcfg_write NULL |
98 | 99 | ||
99 | /* | 100 | /* |
100 | * Methods used to fetch LPAR data when running on an iSeries platform. | 101 | * Methods used to fetch LPAR data when running on an iSeries platform. |
101 | */ | 102 | */ |
102 | static int lparcfg_data(struct seq_file *m, void *v) | 103 | static int lparcfg_data(struct seq_file *m, void *v) |
@@ -168,7 +169,7 @@ static int lparcfg_data(struct seq_file *m, void *v) | |||
168 | #endif /* CONFIG_PPC_ISERIES */ | 169 | #endif /* CONFIG_PPC_ISERIES */ |
169 | 170 | ||
170 | #ifdef CONFIG_PPC_PSERIES | 171 | #ifdef CONFIG_PPC_PSERIES |
171 | /* | 172 | /* |
172 | * Methods used to fetch LPAR data when running on a pSeries platform. | 173 | * Methods used to fetch LPAR data when running on a pSeries platform. |
173 | */ | 174 | */ |
174 | 175 | ||
@@ -177,7 +178,7 @@ static int lparcfg_data(struct seq_file *m, void *v) | |||
177 | * entitled_capacity,unallocated_capacity, | 178 | * entitled_capacity,unallocated_capacity, |
178 | * aggregation, resource_capability). | 179 | * aggregation, resource_capability). |
179 | * | 180 | * |
180 | * R4 = Entitled Processor Capacity Percentage. | 181 | * R4 = Entitled Processor Capacity Percentage. |
181 | * R5 = Unallocated Processor Capacity Percentage. | 182 | * R5 = Unallocated Processor Capacity Percentage. |
182 | * R6 (AABBCCDDEEFFGGHH). | 183 | * R6 (AABBCCDDEEFFGGHH). |
183 | * XXXX - reserved (0) | 184 | * XXXX - reserved (0) |
@@ -190,7 +191,7 @@ static int lparcfg_data(struct seq_file *m, void *v) | |||
190 | * XX - variable processor Capacity Weight | 191 | * XX - variable processor Capacity Weight |
191 | * XX - Unallocated Variable Processor Capacity Weight. | 192 | * XX - Unallocated Variable Processor Capacity Weight. |
192 | * XXXX - Active processors in Physical Processor Pool. | 193 | * XXXX - Active processors in Physical Processor Pool. |
193 | * XXXX - Processors active on platform. | 194 | * XXXX - Processors active on platform. |
194 | */ | 195 | */ |
195 | static unsigned int h_get_ppp(unsigned long *entitled, | 196 | static unsigned int h_get_ppp(unsigned long *entitled, |
196 | unsigned long *unallocated, | 197 | unsigned long *unallocated, |
@@ -273,7 +274,7 @@ static void parse_system_parameter_string(struct seq_file *m) | |||
273 | if (!workbuffer) { | 274 | if (!workbuffer) { |
274 | printk(KERN_ERR "%s %s kmalloc failure at line %d \n", | 275 | printk(KERN_ERR "%s %s kmalloc failure at line %d \n", |
275 | __FILE__, __FUNCTION__, __LINE__); | 276 | __FILE__, __FUNCTION__, __LINE__); |
276 | kfree(local_buffer); | 277 | kfree(local_buffer); |
277 | return; | 278 | return; |
278 | } | 279 | } |
279 | #ifdef LPARCFG_DEBUG | 280 | #ifdef LPARCFG_DEBUG |
@@ -371,7 +372,7 @@ static int lparcfg_data(struct seq_file *m, void *v) | |||
371 | lrdrp = (int *)get_property(rtas_node, "ibm,lrdr-capacity", NULL); | 372 | lrdrp = (int *)get_property(rtas_node, "ibm,lrdr-capacity", NULL); |
372 | 373 | ||
373 | if (lrdrp == NULL) { | 374 | if (lrdrp == NULL) { |
374 | partition_potential_processors = systemcfg->processorCount; | 375 | partition_potential_processors = _systemcfg->processorCount; |
375 | } else { | 376 | } else { |
376 | partition_potential_processors = *(lrdrp + 4); | 377 | partition_potential_processors = *(lrdrp + 4); |
377 | } | 378 | } |
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 3bedb532aed9..f6d84a75ed26 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S | |||
@@ -519,7 +519,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) | |||
519 | * | 519 | * |
520 | * flush_icache_range(unsigned long start, unsigned long stop) | 520 | * flush_icache_range(unsigned long start, unsigned long stop) |
521 | */ | 521 | */ |
522 | _GLOBAL(flush_icache_range) | 522 | _GLOBAL(__flush_icache_range) |
523 | BEGIN_FTR_SECTION | 523 | BEGIN_FTR_SECTION |
524 | blr /* for 601, do nothing */ | 524 | blr /* for 601, do nothing */ |
525 | END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) | 525 | END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) |
@@ -607,27 +607,6 @@ _GLOBAL(invalidate_dcache_range) | |||
607 | sync /* wait for dcbi's to get to ram */ | 607 | sync /* wait for dcbi's to get to ram */ |
608 | blr | 608 | blr |
609 | 609 | ||
610 | #ifdef CONFIG_NOT_COHERENT_CACHE | ||
611 | /* | ||
612 | * 40x cores have 8K or 16K dcache and 32 byte line size. | ||
613 | * 44x has a 32K dcache and 32 byte line size. | ||
614 | * 8xx has 1, 2, 4, 8K variants. | ||
615 | * For now, cover the worst case of the 44x. | ||
616 | * Must be called with external interrupts disabled. | ||
617 | */ | ||
618 | #define CACHE_NWAYS 64 | ||
619 | #define CACHE_NLINES 16 | ||
620 | |||
621 | _GLOBAL(flush_dcache_all) | ||
622 | li r4, (2 * CACHE_NWAYS * CACHE_NLINES) | ||
623 | mtctr r4 | ||
624 | lis r5, KERNELBASE@h | ||
625 | 1: lwz r3, 0(r5) /* Load one word from every line */ | ||
626 | addi r5, r5, L1_CACHE_BYTES | ||
627 | bdnz 1b | ||
628 | blr | ||
629 | #endif /* CONFIG_NOT_COHERENT_CACHE */ | ||
630 | |||
631 | /* | 610 | /* |
632 | * Flush a particular page from the data cache to RAM. | 611 | * Flush a particular page from the data cache to RAM. |
633 | * Note: this is necessary because the instruction cache does *not* | 612 | * Note: this is necessary because the instruction cache does *not* |
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index ae1433da09b2..ae48a002f81a 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S | |||
@@ -89,12 +89,12 @@ _GLOBAL(call_do_softirq) | |||
89 | mtlr r0 | 89 | mtlr r0 |
90 | blr | 90 | blr |
91 | 91 | ||
92 | _GLOBAL(call_handle_IRQ_event) | 92 | _GLOBAL(call___do_IRQ) |
93 | mflr r0 | 93 | mflr r0 |
94 | std r0,16(r1) | 94 | std r0,16(r1) |
95 | stdu r1,THREAD_SIZE-112(r6) | 95 | stdu r1,THREAD_SIZE-112(r5) |
96 | mr r1,r6 | 96 | mr r1,r5 |
97 | bl .handle_IRQ_event | 97 | bl .__do_IRQ |
98 | ld r1,0(r1) | 98 | ld r1,0(r1) |
99 | ld r0,16(r1) | 99 | ld r0,16(r1) |
100 | mtlr r0 | 100 | mtlr r0 |
diff --git a/arch/ppc64/kernel/pacaData.c b/arch/powerpc/kernel/paca.c index 3133c72b28ec..3cf2517c5f91 100644 --- a/arch/ppc64/kernel/pacaData.c +++ b/arch/powerpc/kernel/paca.c | |||
@@ -15,7 +15,7 @@ | |||
15 | #include <asm/processor.h> | 15 | #include <asm/processor.h> |
16 | #include <asm/ptrace.h> | 16 | #include <asm/ptrace.h> |
17 | #include <asm/page.h> | 17 | #include <asm/page.h> |
18 | 18 | #include <asm/systemcfg.h> | |
19 | #include <asm/lppaca.h> | 19 | #include <asm/lppaca.h> |
20 | #include <asm/iseries/it_lp_queue.h> | 20 | #include <asm/iseries/it_lp_queue.h> |
21 | #include <asm/paca.h> | 21 | #include <asm/paca.h> |
@@ -24,15 +24,14 @@ static union { | |||
24 | struct systemcfg data; | 24 | struct systemcfg data; |
25 | u8 page[PAGE_SIZE]; | 25 | u8 page[PAGE_SIZE]; |
26 | } systemcfg_store __attribute__((__section__(".data.page.aligned"))); | 26 | } systemcfg_store __attribute__((__section__(".data.page.aligned"))); |
27 | struct systemcfg *systemcfg = &systemcfg_store.data; | 27 | struct systemcfg *_systemcfg = &systemcfg_store.data; |
28 | EXPORT_SYMBOL(systemcfg); | ||
29 | 28 | ||
30 | 29 | ||
31 | /* This symbol is provided by the linker - let it fill in the paca | 30 | /* This symbol is provided by the linker - let it fill in the paca |
32 | * field correctly */ | 31 | * field correctly */ |
33 | extern unsigned long __toc_start; | 32 | extern unsigned long __toc_start; |
34 | 33 | ||
35 | /* The Paca is an array with one entry per processor. Each contains an | 34 | /* The Paca is an array with one entry per processor. Each contains an |
36 | * lppaca, which contains the information shared between the | 35 | * lppaca, which contains the information shared between the |
37 | * hypervisor and Linux. Each also contains an ItLpRegSave area which | 36 | * hypervisor and Linux. Each also contains an ItLpRegSave area which |
38 | * is used by the hypervisor to save registers. | 37 | * is used by the hypervisor to save registers. |
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index 47d6f7e2ea9f..5dcf4ba05ee8 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <asm/cputable.h> | 44 | #include <asm/cputable.h> |
45 | #include <asm/btext.h> | 45 | #include <asm/btext.h> |
46 | #include <asm/div64.h> | 46 | #include <asm/div64.h> |
47 | #include <asm/signal.h> | ||
47 | 48 | ||
48 | #ifdef CONFIG_8xx | 49 | #ifdef CONFIG_8xx |
49 | #include <asm/commproc.h> | 50 | #include <asm/commproc.h> |
@@ -56,7 +57,6 @@ extern void machine_check_exception(struct pt_regs *regs); | |||
56 | extern void alignment_exception(struct pt_regs *regs); | 57 | extern void alignment_exception(struct pt_regs *regs); |
57 | extern void program_check_exception(struct pt_regs *regs); | 58 | extern void program_check_exception(struct pt_regs *regs); |
58 | extern void single_step_exception(struct pt_regs *regs); | 59 | extern void single_step_exception(struct pt_regs *regs); |
59 | extern int do_signal(sigset_t *, struct pt_regs *); | ||
60 | extern int pmac_newworld; | 60 | extern int pmac_newworld; |
61 | extern int sys_sigreturn(struct pt_regs *regs); | 61 | extern int sys_sigreturn(struct pt_regs *regs); |
62 | 62 | ||
@@ -188,9 +188,6 @@ EXPORT_SYMBOL(adb_try_handler_change); | |||
188 | EXPORT_SYMBOL(cuda_request); | 188 | EXPORT_SYMBOL(cuda_request); |
189 | EXPORT_SYMBOL(cuda_poll); | 189 | EXPORT_SYMBOL(cuda_poll); |
190 | #endif /* CONFIG_ADB_CUDA */ | 190 | #endif /* CONFIG_ADB_CUDA */ |
191 | #if defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_PPC32) | ||
192 | EXPORT_SYMBOL(_machine); | ||
193 | #endif | ||
194 | #ifdef CONFIG_PPC_PMAC | 191 | #ifdef CONFIG_PPC_PMAC |
195 | EXPORT_SYMBOL(sys_ctrler); | 192 | EXPORT_SYMBOL(sys_ctrler); |
196 | #endif | 193 | #endif |
diff --git a/arch/ppc64/kernel/proc_ppc64.c b/arch/powerpc/kernel/proc_ppc64.c index 24e955ee9487..a1c19502fe8b 100644 --- a/arch/ppc64/kernel/proc_ppc64.c +++ b/arch/powerpc/kernel/proc_ppc64.c | |||
@@ -1,18 +1,16 @@ | |||
1 | /* | 1 | /* |
2 | * arch/ppc64/kernel/proc_ppc64.c | ||
3 | * | ||
4 | * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM Corporation | 2 | * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM Corporation |
5 | * | 3 | * |
6 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 5 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or | 6 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. | 7 | * (at your option) any later version. |
10 | * | 8 | * |
11 | * This program is distributed in the hope that it will be useful, | 9 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
15 | * | 13 | * |
16 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
@@ -53,7 +51,7 @@ static int __init proc_ppc64_create(void) | |||
53 | if (!root) | 51 | if (!root) |
54 | return 1; | 52 | return 1; |
55 | 53 | ||
56 | if (!(systemcfg->platform & (PLATFORM_PSERIES | PLATFORM_CELL))) | 54 | if (!(platform_is_pseries() || _machine == PLATFORM_CELL)) |
57 | return 0; | 55 | return 0; |
58 | 56 | ||
59 | if (!proc_mkdir("rtas", root)) | 57 | if (!proc_mkdir("rtas", root)) |
@@ -74,7 +72,7 @@ static int __init proc_ppc64_init(void) | |||
74 | if (!pde) | 72 | if (!pde) |
75 | return 1; | 73 | return 1; |
76 | pde->nlink = 1; | 74 | pde->nlink = 1; |
77 | pde->data = systemcfg; | 75 | pde->data = _systemcfg; |
78 | pde->size = PAGE_SIZE; | 76 | pde->size = PAGE_SIZE; |
79 | pde->proc_fops = &page_map_fops; | 77 | pde->proc_fops = &page_map_fops; |
80 | 78 | ||
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index f645adb57534..6a5b468edb4d 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
@@ -48,9 +48,6 @@ | |||
48 | #include <asm/machdep.h> | 48 | #include <asm/machdep.h> |
49 | #include <asm/pSeries_reconfig.h> | 49 | #include <asm/pSeries_reconfig.h> |
50 | #include <asm/pci-bridge.h> | 50 | #include <asm/pci-bridge.h> |
51 | #ifdef CONFIG_PPC64 | ||
52 | #include <asm/systemcfg.h> | ||
53 | #endif | ||
54 | 51 | ||
55 | #ifdef DEBUG | 52 | #ifdef DEBUG |
56 | #define DBG(fmt...) printk(KERN_ERR fmt) | 53 | #define DBG(fmt...) printk(KERN_ERR fmt) |
@@ -74,10 +71,6 @@ struct isa_reg_property { | |||
74 | typedef int interpret_func(struct device_node *, unsigned long *, | 71 | typedef int interpret_func(struct device_node *, unsigned long *, |
75 | int, int, int); | 72 | int, int, int); |
76 | 73 | ||
77 | extern struct rtas_t rtas; | ||
78 | extern struct lmb lmb; | ||
79 | extern unsigned long klimit; | ||
80 | |||
81 | static int __initdata dt_root_addr_cells; | 74 | static int __initdata dt_root_addr_cells; |
82 | static int __initdata dt_root_size_cells; | 75 | static int __initdata dt_root_size_cells; |
83 | 76 | ||
@@ -391,7 +384,7 @@ static int __devinit finish_node_interrupts(struct device_node *np, | |||
391 | 384 | ||
392 | #ifdef CONFIG_PPC64 | 385 | #ifdef CONFIG_PPC64 |
393 | /* We offset irq numbers for the u3 MPIC by 128 in PowerMac */ | 386 | /* We offset irq numbers for the u3 MPIC by 128 in PowerMac */ |
394 | if (systemcfg->platform == PLATFORM_POWERMAC && ic && ic->parent) { | 387 | if (_machine == PLATFORM_POWERMAC && ic && ic->parent) { |
395 | char *name = get_property(ic->parent, "name", NULL); | 388 | char *name = get_property(ic->parent, "name", NULL); |
396 | if (name && !strcmp(name, "u3")) | 389 | if (name && !strcmp(name, "u3")) |
397 | np->intrs[intrcount].line += 128; | 390 | np->intrs[intrcount].line += 128; |
@@ -1087,9 +1080,9 @@ void __init unflatten_device_tree(void) | |||
1087 | static int __init early_init_dt_scan_cpus(unsigned long node, | 1080 | static int __init early_init_dt_scan_cpus(unsigned long node, |
1088 | const char *uname, int depth, void *data) | 1081 | const char *uname, int depth, void *data) |
1089 | { | 1082 | { |
1090 | char *type = of_get_flat_dt_prop(node, "device_type", NULL); | ||
1091 | u32 *prop; | 1083 | u32 *prop; |
1092 | unsigned long size = 0; | 1084 | unsigned long size; |
1085 | char *type = of_get_flat_dt_prop(node, "device_type", &size); | ||
1093 | 1086 | ||
1094 | /* We are scanning "cpu" nodes only */ | 1087 | /* We are scanning "cpu" nodes only */ |
1095 | if (type == NULL || strcmp(type, "cpu") != 0) | 1088 | if (type == NULL || strcmp(type, "cpu") != 0) |
@@ -1115,7 +1108,7 @@ static int __init early_init_dt_scan_cpus(unsigned long node, | |||
1115 | 1108 | ||
1116 | #ifdef CONFIG_ALTIVEC | 1109 | #ifdef CONFIG_ALTIVEC |
1117 | /* Check if we have a VMX and eventually update CPU features */ | 1110 | /* Check if we have a VMX and eventually update CPU features */ |
1118 | prop = (u32 *)of_get_flat_dt_prop(node, "ibm,vmx", &size); | 1111 | prop = (u32 *)of_get_flat_dt_prop(node, "ibm,vmx", NULL); |
1119 | if (prop && (*prop) > 0) { | 1112 | if (prop && (*prop) > 0) { |
1120 | cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC; | 1113 | cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC; |
1121 | cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC; | 1114 | cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC; |
@@ -1161,13 +1154,9 @@ static int __init early_init_dt_scan_chosen(unsigned long node, | |||
1161 | prop = (u32 *)of_get_flat_dt_prop(node, "linux,platform", NULL); | 1154 | prop = (u32 *)of_get_flat_dt_prop(node, "linux,platform", NULL); |
1162 | if (prop == NULL) | 1155 | if (prop == NULL) |
1163 | return 0; | 1156 | return 0; |
1164 | #ifdef CONFIG_PPC64 | ||
1165 | systemcfg->platform = *prop; | ||
1166 | #else | ||
1167 | #ifdef CONFIG_PPC_MULTIPLATFORM | 1157 | #ifdef CONFIG_PPC_MULTIPLATFORM |
1168 | _machine = *prop; | 1158 | _machine = *prop; |
1169 | #endif | 1159 | #endif |
1170 | #endif | ||
1171 | 1160 | ||
1172 | #ifdef CONFIG_PPC64 | 1161 | #ifdef CONFIG_PPC64 |
1173 | /* check if iommu is forced on or off */ | 1162 | /* check if iommu is forced on or off */ |
@@ -1264,7 +1253,14 @@ static int __init early_init_dt_scan_memory(unsigned long node, | |||
1264 | unsigned long l; | 1253 | unsigned long l; |
1265 | 1254 | ||
1266 | /* We are scanning "memory" nodes only */ | 1255 | /* We are scanning "memory" nodes only */ |
1267 | if (type == NULL || strcmp(type, "memory") != 0) | 1256 | if (type == NULL) { |
1257 | /* | ||
1258 | * The longtrail doesn't have a device_type on the | ||
1259 | * /memory node, so look for the node called /memory@0. | ||
1260 | */ | ||
1261 | if (depth != 1 || strcmp(uname, "memory@0") != 0) | ||
1262 | return 0; | ||
1263 | } else if (strcmp(type, "memory") != 0) | ||
1268 | return 0; | 1264 | return 0; |
1269 | 1265 | ||
1270 | reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l); | 1266 | reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l); |
@@ -1339,9 +1335,6 @@ void __init early_init_devtree(void *params) | |||
1339 | of_scan_flat_dt(early_init_dt_scan_memory, NULL); | 1335 | of_scan_flat_dt(early_init_dt_scan_memory, NULL); |
1340 | lmb_enforce_memory_limit(memory_limit); | 1336 | lmb_enforce_memory_limit(memory_limit); |
1341 | lmb_analyze(); | 1337 | lmb_analyze(); |
1342 | #ifdef CONFIG_PPC64 | ||
1343 | systemcfg->physicalMemorySize = lmb_phys_mem_size(); | ||
1344 | #endif | ||
1345 | lmb_reserve(0, __pa(klimit)); | 1338 | lmb_reserve(0, __pa(klimit)); |
1346 | 1339 | ||
1347 | DBG("Phys. mem: %lx\n", lmb_phys_mem_size()); | 1340 | DBG("Phys. mem: %lx\n", lmb_phys_mem_size()); |
@@ -1908,7 +1901,7 @@ static int of_finish_dynamic_node(struct device_node *node, | |||
1908 | /* We don't support that function on PowerMac, at least | 1901 | /* We don't support that function on PowerMac, at least |
1909 | * not yet | 1902 | * not yet |
1910 | */ | 1903 | */ |
1911 | if (systemcfg->platform == PLATFORM_POWERMAC) | 1904 | if (_machine == PLATFORM_POWERMAC) |
1912 | return -ENODEV; | 1905 | return -ENODEV; |
1913 | 1906 | ||
1914 | /* fix up new node's linux_phandle field */ | 1907 | /* fix up new node's linux_phandle field */ |
@@ -1992,9 +1985,11 @@ int prom_add_property(struct device_node* np, struct property* prop) | |||
1992 | *next = prop; | 1985 | *next = prop; |
1993 | write_unlock(&devtree_lock); | 1986 | write_unlock(&devtree_lock); |
1994 | 1987 | ||
1988 | #ifdef CONFIG_PROC_DEVICETREE | ||
1995 | /* try to add to proc as well if it was initialized */ | 1989 | /* try to add to proc as well if it was initialized */ |
1996 | if (np->pde) | 1990 | if (np->pde) |
1997 | proc_device_tree_add_prop(np->pde, prop); | 1991 | proc_device_tree_add_prop(np->pde, prop); |
1992 | #endif /* CONFIG_PROC_DEVICETREE */ | ||
1998 | 1993 | ||
1999 | return 0; | 1994 | return 0; |
2000 | } | 1995 | } |
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 6dc33d19fc2a..4ce0105c308e 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c | |||
@@ -94,11 +94,17 @@ extern const struct linux_logo logo_linux_clut224; | |||
94 | #ifdef CONFIG_PPC64 | 94 | #ifdef CONFIG_PPC64 |
95 | #define RELOC(x) (*PTRRELOC(&(x))) | 95 | #define RELOC(x) (*PTRRELOC(&(x))) |
96 | #define ADDR(x) (u32) add_reloc_offset((unsigned long)(x)) | 96 | #define ADDR(x) (u32) add_reloc_offset((unsigned long)(x)) |
97 | #define OF_WORKAROUNDS 0 | ||
97 | #else | 98 | #else |
98 | #define RELOC(x) (x) | 99 | #define RELOC(x) (x) |
99 | #define ADDR(x) (u32) (x) | 100 | #define ADDR(x) (u32) (x) |
101 | #define OF_WORKAROUNDS of_workarounds | ||
102 | int of_workarounds; | ||
100 | #endif | 103 | #endif |
101 | 104 | ||
105 | #define OF_WA_CLAIM 1 /* do phys/virt claim separately, then map */ | ||
106 | #define OF_WA_LONGTRAIL 2 /* work around longtrail bugs */ | ||
107 | |||
102 | #define PROM_BUG() do { \ | 108 | #define PROM_BUG() do { \ |
103 | prom_printf("kernel BUG at %s line 0x%x!\n", \ | 109 | prom_printf("kernel BUG at %s line 0x%x!\n", \ |
104 | RELOC(__FILE__), __LINE__); \ | 110 | RELOC(__FILE__), __LINE__); \ |
@@ -111,11 +117,6 @@ extern const struct linux_logo logo_linux_clut224; | |||
111 | #define prom_debug(x...) | 117 | #define prom_debug(x...) |
112 | #endif | 118 | #endif |
113 | 119 | ||
114 | #ifdef CONFIG_PPC32 | ||
115 | #define PLATFORM_POWERMAC _MACH_Pmac | ||
116 | #define PLATFORM_CHRP _MACH_chrp | ||
117 | #endif | ||
118 | |||
119 | 120 | ||
120 | typedef u32 prom_arg_t; | 121 | typedef u32 prom_arg_t; |
121 | 122 | ||
@@ -128,10 +129,11 @@ struct prom_args { | |||
128 | 129 | ||
129 | struct prom_t { | 130 | struct prom_t { |
130 | ihandle root; | 131 | ihandle root; |
131 | ihandle chosen; | 132 | phandle chosen; |
132 | int cpu; | 133 | int cpu; |
133 | ihandle stdout; | 134 | ihandle stdout; |
134 | ihandle mmumap; | 135 | ihandle mmumap; |
136 | ihandle memory; | ||
135 | }; | 137 | }; |
136 | 138 | ||
137 | struct mem_map_entry { | 139 | struct mem_map_entry { |
@@ -360,16 +362,36 @@ static void __init prom_printf(const char *format, ...) | |||
360 | static unsigned int __init prom_claim(unsigned long virt, unsigned long size, | 362 | static unsigned int __init prom_claim(unsigned long virt, unsigned long size, |
361 | unsigned long align) | 363 | unsigned long align) |
362 | { | 364 | { |
363 | int ret; | ||
364 | struct prom_t *_prom = &RELOC(prom); | 365 | struct prom_t *_prom = &RELOC(prom); |
365 | 366 | ||
366 | ret = call_prom("claim", 3, 1, (prom_arg_t)virt, (prom_arg_t)size, | 367 | if (align == 0 && (OF_WORKAROUNDS & OF_WA_CLAIM)) { |
367 | (prom_arg_t)align); | 368 | /* |
368 | if (ret != -1 && _prom->mmumap != 0) | 369 | * Old OF requires we claim physical and virtual separately |
369 | /* old pmacs need us to map as well */ | 370 | * and then map explicitly (assuming virtual mode) |
371 | */ | ||
372 | int ret; | ||
373 | prom_arg_t result; | ||
374 | |||
375 | ret = call_prom_ret("call-method", 5, 2, &result, | ||
376 | ADDR("claim"), _prom->memory, | ||
377 | align, size, virt); | ||
378 | if (ret != 0 || result == -1) | ||
379 | return -1; | ||
380 | ret = call_prom_ret("call-method", 5, 2, &result, | ||
381 | ADDR("claim"), _prom->mmumap, | ||
382 | align, size, virt); | ||
383 | if (ret != 0) { | ||
384 | call_prom("call-method", 4, 1, ADDR("release"), | ||
385 | _prom->memory, size, virt); | ||
386 | return -1; | ||
387 | } | ||
388 | /* the 0x12 is M (coherence) + PP == read/write */ | ||
370 | call_prom("call-method", 6, 1, | 389 | call_prom("call-method", 6, 1, |
371 | ADDR("map"), _prom->mmumap, 0, size, virt, virt); | 390 | ADDR("map"), _prom->mmumap, 0x12, size, virt, virt); |
372 | return ret; | 391 | return virt; |
392 | } | ||
393 | return call_prom("claim", 3, 1, (prom_arg_t)virt, (prom_arg_t)size, | ||
394 | (prom_arg_t)align); | ||
373 | } | 395 | } |
374 | 396 | ||
375 | static void __init __attribute__((noreturn)) prom_panic(const char *reason) | 397 | static void __init __attribute__((noreturn)) prom_panic(const char *reason) |
@@ -415,11 +437,52 @@ static int inline prom_getproplen(phandle node, const char *pname) | |||
415 | return call_prom("getproplen", 2, 1, node, ADDR(pname)); | 437 | return call_prom("getproplen", 2, 1, node, ADDR(pname)); |
416 | } | 438 | } |
417 | 439 | ||
418 | static int inline prom_setprop(phandle node, const char *pname, | 440 | static void add_string(char **str, const char *q) |
419 | void *value, size_t valuelen) | ||
420 | { | 441 | { |
421 | return call_prom("setprop", 4, 1, node, ADDR(pname), | 442 | char *p = *str; |
422 | (u32)(unsigned long) value, (u32) valuelen); | 443 | |
444 | while (*q) | ||
445 | *p++ = *q++; | ||
446 | *p++ = ' '; | ||
447 | *str = p; | ||
448 | } | ||
449 | |||
450 | static char *tohex(unsigned int x) | ||
451 | { | ||
452 | static char digits[] = "0123456789abcdef"; | ||
453 | static char result[9]; | ||
454 | int i; | ||
455 | |||
456 | result[8] = 0; | ||
457 | i = 8; | ||
458 | do { | ||
459 | --i; | ||
460 | result[i] = digits[x & 0xf]; | ||
461 | x >>= 4; | ||
462 | } while (x != 0 && i > 0); | ||
463 | return &result[i]; | ||
464 | } | ||
465 | |||
466 | static int __init prom_setprop(phandle node, const char *nodename, | ||
467 | const char *pname, void *value, size_t valuelen) | ||
468 | { | ||
469 | char cmd[256], *p; | ||
470 | |||
471 | if (!(OF_WORKAROUNDS & OF_WA_LONGTRAIL)) | ||
472 | return call_prom("setprop", 4, 1, node, ADDR(pname), | ||
473 | (u32)(unsigned long) value, (u32) valuelen); | ||
474 | |||
475 | /* gah... setprop doesn't work on longtrail, have to use interpret */ | ||
476 | p = cmd; | ||
477 | add_string(&p, "dev"); | ||
478 | add_string(&p, nodename); | ||
479 | add_string(&p, tohex((u32)(unsigned long) value)); | ||
480 | add_string(&p, tohex(valuelen)); | ||
481 | add_string(&p, tohex(ADDR(pname))); | ||
482 | add_string(&p, tohex(strlen(RELOC(pname)))); | ||
483 | add_string(&p, "property"); | ||
484 | *p = 0; | ||
485 | return call_prom("interpret", 1, 1, (u32)(unsigned long) cmd); | ||
423 | } | 486 | } |
424 | 487 | ||
425 | /* We can't use the standard versions because of RELOC headaches. */ | 488 | /* We can't use the standard versions because of RELOC headaches. */ |
@@ -980,7 +1043,7 @@ static void __init prom_instantiate_rtas(void) | |||
980 | 1043 | ||
981 | rtas_inst = call_prom("open", 1, 1, ADDR("/rtas")); | 1044 | rtas_inst = call_prom("open", 1, 1, ADDR("/rtas")); |
982 | if (!IHANDLE_VALID(rtas_inst)) { | 1045 | if (!IHANDLE_VALID(rtas_inst)) { |
983 | prom_printf("opening rtas package failed"); | 1046 | prom_printf("opening rtas package failed (%x)\n", rtas_inst); |
984 | return; | 1047 | return; |
985 | } | 1048 | } |
986 | 1049 | ||
@@ -988,7 +1051,7 @@ static void __init prom_instantiate_rtas(void) | |||
988 | 1051 | ||
989 | if (call_prom_ret("call-method", 3, 2, &entry, | 1052 | if (call_prom_ret("call-method", 3, 2, &entry, |
990 | ADDR("instantiate-rtas"), | 1053 | ADDR("instantiate-rtas"), |
991 | rtas_inst, base) == PROM_ERROR | 1054 | rtas_inst, base) != 0 |
992 | || entry == 0) { | 1055 | || entry == 0) { |
993 | prom_printf(" failed\n"); | 1056 | prom_printf(" failed\n"); |
994 | return; | 1057 | return; |
@@ -997,8 +1060,10 @@ static void __init prom_instantiate_rtas(void) | |||
997 | 1060 | ||
998 | reserve_mem(base, size); | 1061 | reserve_mem(base, size); |
999 | 1062 | ||
1000 | prom_setprop(rtas_node, "linux,rtas-base", &base, sizeof(base)); | 1063 | prom_setprop(rtas_node, "/rtas", "linux,rtas-base", |
1001 | prom_setprop(rtas_node, "linux,rtas-entry", &entry, sizeof(entry)); | 1064 | &base, sizeof(base)); |
1065 | prom_setprop(rtas_node, "/rtas", "linux,rtas-entry", | ||
1066 | &entry, sizeof(entry)); | ||
1002 | 1067 | ||
1003 | prom_debug("rtas base = 0x%x\n", base); | 1068 | prom_debug("rtas base = 0x%x\n", base); |
1004 | prom_debug("rtas entry = 0x%x\n", entry); | 1069 | prom_debug("rtas entry = 0x%x\n", entry); |
@@ -1089,10 +1154,6 @@ static void __init prom_initialize_tce_table(void) | |||
1089 | if (base < local_alloc_bottom) | 1154 | if (base < local_alloc_bottom) |
1090 | local_alloc_bottom = base; | 1155 | local_alloc_bottom = base; |
1091 | 1156 | ||
1092 | /* Save away the TCE table attributes for later use. */ | ||
1093 | prom_setprop(node, "linux,tce-base", &base, sizeof(base)); | ||
1094 | prom_setprop(node, "linux,tce-size", &minsize, sizeof(minsize)); | ||
1095 | |||
1096 | /* It seems OF doesn't null-terminate the path :-( */ | 1157 | /* It seems OF doesn't null-terminate the path :-( */ |
1097 | memset(path, 0, sizeof(path)); | 1158 | memset(path, 0, sizeof(path)); |
1098 | /* Call OF to setup the TCE hardware */ | 1159 | /* Call OF to setup the TCE hardware */ |
@@ -1101,6 +1162,10 @@ static void __init prom_initialize_tce_table(void) | |||
1101 | prom_printf("package-to-path failed\n"); | 1162 | prom_printf("package-to-path failed\n"); |
1102 | } | 1163 | } |
1103 | 1164 | ||
1165 | /* Save away the TCE table attributes for later use. */ | ||
1166 | prom_setprop(node, path, "linux,tce-base", &base, sizeof(base)); | ||
1167 | prom_setprop(node, path, "linux,tce-size", &minsize, sizeof(minsize)); | ||
1168 | |||
1104 | prom_debug("TCE table: %s\n", path); | 1169 | prom_debug("TCE table: %s\n", path); |
1105 | prom_debug("\tnode = 0x%x\n", node); | 1170 | prom_debug("\tnode = 0x%x\n", node); |
1106 | prom_debug("\tbase = 0x%x\n", base); | 1171 | prom_debug("\tbase = 0x%x\n", base); |
@@ -1342,6 +1407,7 @@ static void __init prom_init_client_services(unsigned long pp) | |||
1342 | /* | 1407 | /* |
1343 | * For really old powermacs, we need to map things we claim. | 1408 | * For really old powermacs, we need to map things we claim. |
1344 | * For that, we need the ihandle of the mmu. | 1409 | * For that, we need the ihandle of the mmu. |
1410 | * Also, on the longtrail, we need to work around other bugs. | ||
1345 | */ | 1411 | */ |
1346 | static void __init prom_find_mmu(void) | 1412 | static void __init prom_find_mmu(void) |
1347 | { | 1413 | { |
@@ -1355,12 +1421,19 @@ static void __init prom_find_mmu(void) | |||
1355 | if (prom_getprop(oprom, "model", version, sizeof(version)) <= 0) | 1421 | if (prom_getprop(oprom, "model", version, sizeof(version)) <= 0) |
1356 | return; | 1422 | return; |
1357 | version[sizeof(version) - 1] = 0; | 1423 | version[sizeof(version) - 1] = 0; |
1358 | prom_printf("OF version is '%s'\n", version); | ||
1359 | /* XXX might need to add other versions here */ | 1424 | /* XXX might need to add other versions here */ |
1360 | if (strcmp(version, "Open Firmware, 1.0.5") != 0) | 1425 | if (strcmp(version, "Open Firmware, 1.0.5") == 0) |
1426 | of_workarounds = OF_WA_CLAIM; | ||
1427 | else if (strncmp(version, "FirmWorks,3.", 12) == 0) { | ||
1428 | of_workarounds = OF_WA_CLAIM | OF_WA_LONGTRAIL; | ||
1429 | call_prom("interpret", 1, 1, "dev /memory 0 to allow-reclaim"); | ||
1430 | } else | ||
1361 | return; | 1431 | return; |
1432 | _prom->memory = call_prom("open", 1, 1, ADDR("/memory")); | ||
1362 | prom_getprop(_prom->chosen, "mmu", &_prom->mmumap, | 1433 | prom_getprop(_prom->chosen, "mmu", &_prom->mmumap, |
1363 | sizeof(_prom->mmumap)); | 1434 | sizeof(_prom->mmumap)); |
1435 | if (!IHANDLE_VALID(_prom->memory) || !IHANDLE_VALID(_prom->mmumap)) | ||
1436 | of_workarounds &= ~OF_WA_CLAIM; /* hmmm */ | ||
1364 | } | 1437 | } |
1365 | #else | 1438 | #else |
1366 | #define prom_find_mmu() | 1439 | #define prom_find_mmu() |
@@ -1382,16 +1455,17 @@ static void __init prom_init_stdout(void) | |||
1382 | memset(path, 0, 256); | 1455 | memset(path, 0, 256); |
1383 | call_prom("instance-to-path", 3, 1, _prom->stdout, path, 255); | 1456 | call_prom("instance-to-path", 3, 1, _prom->stdout, path, 255); |
1384 | val = call_prom("instance-to-package", 1, 1, _prom->stdout); | 1457 | val = call_prom("instance-to-package", 1, 1, _prom->stdout); |
1385 | prom_setprop(_prom->chosen, "linux,stdout-package", &val, sizeof(val)); | 1458 | prom_setprop(_prom->chosen, "/chosen", "linux,stdout-package", |
1459 | &val, sizeof(val)); | ||
1386 | prom_printf("OF stdout device is: %s\n", RELOC(of_stdout_device)); | 1460 | prom_printf("OF stdout device is: %s\n", RELOC(of_stdout_device)); |
1387 | prom_setprop(_prom->chosen, "linux,stdout-path", | 1461 | prom_setprop(_prom->chosen, "/chosen", "linux,stdout-path", |
1388 | RELOC(of_stdout_device), strlen(RELOC(of_stdout_device))+1); | 1462 | path, strlen(path) + 1); |
1389 | 1463 | ||
1390 | /* If it's a display, note it */ | 1464 | /* If it's a display, note it */ |
1391 | memset(type, 0, sizeof(type)); | 1465 | memset(type, 0, sizeof(type)); |
1392 | prom_getprop(val, "device_type", type, sizeof(type)); | 1466 | prom_getprop(val, "device_type", type, sizeof(type)); |
1393 | if (strcmp(type, RELOC("display")) == 0) | 1467 | if (strcmp(type, RELOC("display")) == 0) |
1394 | prom_setprop(val, "linux,boot-display", NULL, 0); | 1468 | prom_setprop(val, path, "linux,boot-display", NULL, 0); |
1395 | } | 1469 | } |
1396 | 1470 | ||
1397 | static void __init prom_close_stdin(void) | 1471 | static void __init prom_close_stdin(void) |
@@ -1514,7 +1588,7 @@ static void __init prom_check_displays(void) | |||
1514 | 1588 | ||
1515 | /* Success */ | 1589 | /* Success */ |
1516 | prom_printf("done\n"); | 1590 | prom_printf("done\n"); |
1517 | prom_setprop(node, "linux,opened", NULL, 0); | 1591 | prom_setprop(node, path, "linux,opened", NULL, 0); |
1518 | 1592 | ||
1519 | /* Setup a usable color table when the appropriate | 1593 | /* Setup a usable color table when the appropriate |
1520 | * method is available. Should update this to set-colors */ | 1594 | * method is available. Should update this to set-colors */ |
@@ -1884,9 +1958,11 @@ static void __init fixup_device_tree(void) | |||
1884 | /* interrupt on this revision of u3 is number 0 and level */ | 1958 | /* interrupt on this revision of u3 is number 0 and level */ |
1885 | interrupts[0] = 0; | 1959 | interrupts[0] = 0; |
1886 | interrupts[1] = 1; | 1960 | interrupts[1] = 1; |
1887 | prom_setprop(i2c, "interrupts", &interrupts, sizeof(interrupts)); | 1961 | prom_setprop(i2c, "/u3@0,f8000000/i2c@f8001000", "interrupts", |
1962 | &interrupts, sizeof(interrupts)); | ||
1888 | parent = (u32)mpic; | 1963 | parent = (u32)mpic; |
1889 | prom_setprop(i2c, "interrupt-parent", &parent, sizeof(parent)); | 1964 | prom_setprop(i2c, "/u3@0,f8000000/i2c@f8001000", "interrupt-parent", |
1965 | &parent, sizeof(parent)); | ||
1890 | #endif | 1966 | #endif |
1891 | } | 1967 | } |
1892 | 1968 | ||
@@ -1922,11 +1998,11 @@ static void __init prom_check_initrd(unsigned long r3, unsigned long r4) | |||
1922 | RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4; | 1998 | RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4; |
1923 | 1999 | ||
1924 | val = RELOC(prom_initrd_start); | 2000 | val = RELOC(prom_initrd_start); |
1925 | prom_setprop(_prom->chosen, "linux,initrd-start", &val, | 2001 | prom_setprop(_prom->chosen, "/chosen", "linux,initrd-start", |
1926 | sizeof(val)); | 2002 | &val, sizeof(val)); |
1927 | val = RELOC(prom_initrd_end); | 2003 | val = RELOC(prom_initrd_end); |
1928 | prom_setprop(_prom->chosen, "linux,initrd-end", &val, | 2004 | prom_setprop(_prom->chosen, "/chosen", "linux,initrd-end", |
1929 | sizeof(val)); | 2005 | &val, sizeof(val)); |
1930 | 2006 | ||
1931 | reserve_mem(RELOC(prom_initrd_start), | 2007 | reserve_mem(RELOC(prom_initrd_start), |
1932 | RELOC(prom_initrd_end) - RELOC(prom_initrd_start)); | 2008 | RELOC(prom_initrd_end) - RELOC(prom_initrd_start)); |
@@ -1969,14 +2045,15 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, | |||
1969 | prom_init_client_services(pp); | 2045 | prom_init_client_services(pp); |
1970 | 2046 | ||
1971 | /* | 2047 | /* |
1972 | * Init prom stdout device | 2048 | * See if this OF is old enough that we need to do explicit maps |
2049 | * and other workarounds | ||
1973 | */ | 2050 | */ |
1974 | prom_init_stdout(); | 2051 | prom_find_mmu(); |
1975 | 2052 | ||
1976 | /* | 2053 | /* |
1977 | * See if this OF is old enough that we need to do explicit maps | 2054 | * Init prom stdout device |
1978 | */ | 2055 | */ |
1979 | prom_find_mmu(); | 2056 | prom_init_stdout(); |
1980 | 2057 | ||
1981 | /* | 2058 | /* |
1982 | * Check for an initrd | 2059 | * Check for an initrd |
@@ -1989,14 +2066,15 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, | |||
1989 | */ | 2066 | */ |
1990 | RELOC(of_platform) = prom_find_machine_type(); | 2067 | RELOC(of_platform) = prom_find_machine_type(); |
1991 | getprop_rval = RELOC(of_platform); | 2068 | getprop_rval = RELOC(of_platform); |
1992 | prom_setprop(_prom->chosen, "linux,platform", | 2069 | prom_setprop(_prom->chosen, "/chosen", "linux,platform", |
1993 | &getprop_rval, sizeof(getprop_rval)); | 2070 | &getprop_rval, sizeof(getprop_rval)); |
1994 | 2071 | ||
1995 | #ifdef CONFIG_PPC_PSERIES | 2072 | #ifdef CONFIG_PPC_PSERIES |
1996 | /* | 2073 | /* |
1997 | * On pSeries, inform the firmware about our capabilities | 2074 | * On pSeries, inform the firmware about our capabilities |
1998 | */ | 2075 | */ |
1999 | if (RELOC(of_platform) & PLATFORM_PSERIES) | 2076 | if (RELOC(of_platform) == PLATFORM_PSERIES || |
2077 | RELOC(of_platform) == PLATFORM_PSERIES_LPAR) | ||
2000 | prom_send_capabilities(); | 2078 | prom_send_capabilities(); |
2001 | #endif | 2079 | #endif |
2002 | 2080 | ||
@@ -2050,21 +2128,23 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, | |||
2050 | * Fill in some infos for use by the kernel later on | 2128 | * Fill in some infos for use by the kernel later on |
2051 | */ | 2129 | */ |
2052 | if (RELOC(prom_memory_limit)) | 2130 | if (RELOC(prom_memory_limit)) |
2053 | prom_setprop(_prom->chosen, "linux,memory-limit", | 2131 | prom_setprop(_prom->chosen, "/chosen", "linux,memory-limit", |
2054 | &RELOC(prom_memory_limit), | 2132 | &RELOC(prom_memory_limit), |
2055 | sizeof(prom_memory_limit)); | 2133 | sizeof(prom_memory_limit)); |
2056 | #ifdef CONFIG_PPC64 | 2134 | #ifdef CONFIG_PPC64 |
2057 | if (RELOC(ppc64_iommu_off)) | 2135 | if (RELOC(ppc64_iommu_off)) |
2058 | prom_setprop(_prom->chosen, "linux,iommu-off", NULL, 0); | 2136 | prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off", |
2137 | NULL, 0); | ||
2059 | 2138 | ||
2060 | if (RELOC(iommu_force_on)) | 2139 | if (RELOC(iommu_force_on)) |
2061 | prom_setprop(_prom->chosen, "linux,iommu-force-on", NULL, 0); | 2140 | prom_setprop(_prom->chosen, "/chosen", "linux,iommu-force-on", |
2141 | NULL, 0); | ||
2062 | 2142 | ||
2063 | if (RELOC(prom_tce_alloc_start)) { | 2143 | if (RELOC(prom_tce_alloc_start)) { |
2064 | prom_setprop(_prom->chosen, "linux,tce-alloc-start", | 2144 | prom_setprop(_prom->chosen, "/chosen", "linux,tce-alloc-start", |
2065 | &RELOC(prom_tce_alloc_start), | 2145 | &RELOC(prom_tce_alloc_start), |
2066 | sizeof(prom_tce_alloc_start)); | 2146 | sizeof(prom_tce_alloc_start)); |
2067 | prom_setprop(_prom->chosen, "linux,tce-alloc-end", | 2147 | prom_setprop(_prom->chosen, "/chosen", "linux,tce-alloc-end", |
2068 | &RELOC(prom_tce_alloc_end), | 2148 | &RELOC(prom_tce_alloc_end), |
2069 | sizeof(prom_tce_alloc_end)); | 2149 | sizeof(prom_tce_alloc_end)); |
2070 | } | 2150 | } |
@@ -2081,8 +2161,13 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, | |||
2081 | prom_printf("copying OF device tree ...\n"); | 2161 | prom_printf("copying OF device tree ...\n"); |
2082 | flatten_device_tree(); | 2162 | flatten_device_tree(); |
2083 | 2163 | ||
2084 | /* in case stdin is USB and still active on IBM machines... */ | 2164 | /* |
2085 | prom_close_stdin(); | 2165 | * in case stdin is USB and still active on IBM machines... |
2166 | * Unfortunately quiesce crashes on some powermacs if we have | ||
2167 | * closed stdin already (in particular the powerbook 101). | ||
2168 | */ | ||
2169 | if (RELOC(of_platform) != PLATFORM_POWERMAC) | ||
2170 | prom_close_stdin(); | ||
2086 | 2171 | ||
2087 | /* | 2172 | /* |
2088 | * Call OF "quiesce" method to shut down pending DMA's from | 2173 | * Call OF "quiesce" method to shut down pending DMA's from |
diff --git a/arch/powerpc/kernel/rtas-proc.c b/arch/powerpc/kernel/rtas-proc.c index 5bdd5b079d96..ae1a36449ccd 100644 --- a/arch/powerpc/kernel/rtas-proc.c +++ b/arch/powerpc/kernel/rtas-proc.c | |||
@@ -259,7 +259,7 @@ static int __init proc_rtas_init(void) | |||
259 | { | 259 | { |
260 | struct proc_dir_entry *entry; | 260 | struct proc_dir_entry *entry; |
261 | 261 | ||
262 | if (!(systemcfg->platform & PLATFORM_PSERIES)) | 262 | if (_machine != PLATFORM_PSERIES && _machine != PLATFORM_PSERIES_LPAR) |
263 | return 1; | 263 | return 1; |
264 | 264 | ||
265 | rtas_node = of_find_node_by_name(NULL, "rtas"); | 265 | rtas_node = of_find_node_by_name(NULL, "rtas"); |
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 9d4e07f6f1ec..4283fa33f784 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c | |||
@@ -29,9 +29,6 @@ | |||
29 | #include <asm/delay.h> | 29 | #include <asm/delay.h> |
30 | #include <asm/uaccess.h> | 30 | #include <asm/uaccess.h> |
31 | #include <asm/lmb.h> | 31 | #include <asm/lmb.h> |
32 | #ifdef CONFIG_PPC64 | ||
33 | #include <asm/systemcfg.h> | ||
34 | #endif | ||
35 | 32 | ||
36 | struct rtas_t rtas = { | 33 | struct rtas_t rtas = { |
37 | .lock = SPIN_LOCK_UNLOCKED | 34 | .lock = SPIN_LOCK_UNLOCKED |
@@ -671,7 +668,7 @@ void __init rtas_initialize(void) | |||
671 | * the stop-self token if any | 668 | * the stop-self token if any |
672 | */ | 669 | */ |
673 | #ifdef CONFIG_PPC64 | 670 | #ifdef CONFIG_PPC64 |
674 | if (systemcfg->platform == PLATFORM_PSERIES_LPAR) | 671 | if (_machine == PLATFORM_PSERIES_LPAR) |
675 | rtas_region = min(lmb.rmo_size, RTAS_INSTANTIATE_MAX); | 672 | rtas_region = min(lmb.rmo_size, RTAS_INSTANTIATE_MAX); |
676 | #endif | 673 | #endif |
677 | rtas_rmo_buf = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, rtas_region); | 674 | rtas_rmo_buf = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, rtas_region); |
diff --git a/arch/ppc64/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c index 3c3f19192fcc..0e5a8e116653 100644 --- a/arch/ppc64/kernel/rtas_pci.c +++ b/arch/powerpc/kernel/rtas_pci.c | |||
@@ -5,19 +5,19 @@ | |||
5 | * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM | 5 | * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM |
6 | * | 6 | * |
7 | * RTAS specific routines for PCI. | 7 | * RTAS specific routines for PCI. |
8 | * | 8 | * |
9 | * Based on code from pci.c, chrp_pci.c and pSeries_pci.c | 9 | * Based on code from pci.c, chrp_pci.c and pSeries_pci.c |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
13 | * the Free Software Foundation; either version 2 of the License, or | 13 | * the Free Software Foundation; either version 2 of the License, or |
14 | * (at your option) any later version. | 14 | * (at your option) any later version. |
15 | * | 15 | * |
16 | * This program is distributed in the hope that it will be useful, | 16 | * This program is distributed in the hope that it will be useful, |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 | * GNU General Public License for more details. | 19 | * GNU General Public License for more details. |
20 | * | 20 | * |
21 | * You should have received a copy of the GNU General Public License | 21 | * You should have received a copy of the GNU General Public License |
22 | * along with this program; if not, write to the Free Software | 22 | * along with this program; if not, write to the Free Software |
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
@@ -47,7 +47,7 @@ static int write_pci_config; | |||
47 | static int ibm_read_pci_config; | 47 | static int ibm_read_pci_config; |
48 | static int ibm_write_pci_config; | 48 | static int ibm_write_pci_config; |
49 | 49 | ||
50 | static int config_access_valid(struct pci_dn *dn, int where) | 50 | static inline int config_access_valid(struct pci_dn *dn, int where) |
51 | { | 51 | { |
52 | if (where < 256) | 52 | if (where < 256) |
53 | return 1; | 53 | return 1; |
@@ -72,16 +72,14 @@ static int of_device_available(struct device_node * dn) | |||
72 | return 0; | 72 | return 0; |
73 | } | 73 | } |
74 | 74 | ||
75 | static int rtas_read_config(struct device_node *dn, int where, int size, u32 *val) | 75 | static int rtas_read_config(struct pci_dn *pdn, int where, int size, u32 *val) |
76 | { | 76 | { |
77 | int returnval = -1; | 77 | int returnval = -1; |
78 | unsigned long buid, addr; | 78 | unsigned long buid, addr; |
79 | int ret; | 79 | int ret; |
80 | struct pci_dn *pdn; | ||
81 | 80 | ||
82 | if (!dn || !dn->data) | 81 | if (!pdn) |
83 | return PCIBIOS_DEVICE_NOT_FOUND; | 82 | return PCIBIOS_DEVICE_NOT_FOUND; |
84 | pdn = dn->data; | ||
85 | if (!config_access_valid(pdn, where)) | 83 | if (!config_access_valid(pdn, where)) |
86 | return PCIBIOS_BAD_REGISTER_NUMBER; | 84 | return PCIBIOS_BAD_REGISTER_NUMBER; |
87 | 85 | ||
@@ -90,7 +88,7 @@ static int rtas_read_config(struct device_node *dn, int where, int size, u32 *va | |||
90 | buid = pdn->phb->buid; | 88 | buid = pdn->phb->buid; |
91 | if (buid) { | 89 | if (buid) { |
92 | ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval, | 90 | ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval, |
93 | addr, buid >> 32, buid & 0xffffffff, size); | 91 | addr, BUID_HI(buid), BUID_LO(buid), size); |
94 | } else { | 92 | } else { |
95 | ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, size); | 93 | ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, size); |
96 | } | 94 | } |
@@ -100,7 +98,7 @@ static int rtas_read_config(struct device_node *dn, int where, int size, u32 *va | |||
100 | return PCIBIOS_DEVICE_NOT_FOUND; | 98 | return PCIBIOS_DEVICE_NOT_FOUND; |
101 | 99 | ||
102 | if (returnval == EEH_IO_ERROR_VALUE(size) && | 100 | if (returnval == EEH_IO_ERROR_VALUE(size) && |
103 | eeh_dn_check_failure (dn, NULL)) | 101 | eeh_dn_check_failure (pdn->node, NULL)) |
104 | return PCIBIOS_DEVICE_NOT_FOUND; | 102 | return PCIBIOS_DEVICE_NOT_FOUND; |
105 | 103 | ||
106 | return PCIBIOS_SUCCESSFUL; | 104 | return PCIBIOS_SUCCESSFUL; |
@@ -118,23 +116,23 @@ static int rtas_pci_read_config(struct pci_bus *bus, | |||
118 | busdn = bus->sysdata; /* must be a phb */ | 116 | busdn = bus->sysdata; /* must be a phb */ |
119 | 117 | ||
120 | /* Search only direct children of the bus */ | 118 | /* Search only direct children of the bus */ |
121 | for (dn = busdn->child; dn; dn = dn->sibling) | 119 | for (dn = busdn->child; dn; dn = dn->sibling) { |
122 | if (dn->data && PCI_DN(dn)->devfn == devfn | 120 | struct pci_dn *pdn = PCI_DN(dn); |
121 | if (pdn && pdn->devfn == devfn | ||
123 | && of_device_available(dn)) | 122 | && of_device_available(dn)) |
124 | return rtas_read_config(dn, where, size, val); | 123 | return rtas_read_config(pdn, where, size, val); |
124 | } | ||
125 | 125 | ||
126 | return PCIBIOS_DEVICE_NOT_FOUND; | 126 | return PCIBIOS_DEVICE_NOT_FOUND; |
127 | } | 127 | } |
128 | 128 | ||
129 | int rtas_write_config(struct device_node *dn, int where, int size, u32 val) | 129 | int rtas_write_config(struct pci_dn *pdn, int where, int size, u32 val) |
130 | { | 130 | { |
131 | unsigned long buid, addr; | 131 | unsigned long buid, addr; |
132 | int ret; | 132 | int ret; |
133 | struct pci_dn *pdn; | ||
134 | 133 | ||
135 | if (!dn || !dn->data) | 134 | if (!pdn) |
136 | return PCIBIOS_DEVICE_NOT_FOUND; | 135 | return PCIBIOS_DEVICE_NOT_FOUND; |
137 | pdn = dn->data; | ||
138 | if (!config_access_valid(pdn, where)) | 136 | if (!config_access_valid(pdn, where)) |
139 | return PCIBIOS_BAD_REGISTER_NUMBER; | 137 | return PCIBIOS_BAD_REGISTER_NUMBER; |
140 | 138 | ||
@@ -142,7 +140,8 @@ int rtas_write_config(struct device_node *dn, int where, int size, u32 val) | |||
142 | (pdn->devfn << 8) | (where & 0xff); | 140 | (pdn->devfn << 8) | (where & 0xff); |
143 | buid = pdn->phb->buid; | 141 | buid = pdn->phb->buid; |
144 | if (buid) { | 142 | if (buid) { |
145 | ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, buid >> 32, buid & 0xffffffff, size, (ulong) val); | 143 | ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, |
144 | BUID_HI(buid), BUID_LO(buid), size, (ulong) val); | ||
146 | } else { | 145 | } else { |
147 | ret = rtas_call(write_pci_config, 3, 1, NULL, addr, size, (ulong)val); | 146 | ret = rtas_call(write_pci_config, 3, 1, NULL, addr, size, (ulong)val); |
148 | } | 147 | } |
@@ -165,10 +164,12 @@ static int rtas_pci_write_config(struct pci_bus *bus, | |||
165 | busdn = bus->sysdata; /* must be a phb */ | 164 | busdn = bus->sysdata; /* must be a phb */ |
166 | 165 | ||
167 | /* Search only direct children of the bus */ | 166 | /* Search only direct children of the bus */ |
168 | for (dn = busdn->child; dn; dn = dn->sibling) | 167 | for (dn = busdn->child; dn; dn = dn->sibling) { |
169 | if (dn->data && PCI_DN(dn)->devfn == devfn | 168 | struct pci_dn *pdn = PCI_DN(dn); |
169 | if (pdn && pdn->devfn == devfn | ||
170 | && of_device_available(dn)) | 170 | && of_device_available(dn)) |
171 | return rtas_write_config(dn, where, size, val); | 171 | return rtas_write_config(pdn, where, size, val); |
172 | } | ||
172 | return PCIBIOS_DEVICE_NOT_FOUND; | 173 | return PCIBIOS_DEVICE_NOT_FOUND; |
173 | } | 174 | } |
174 | 175 | ||
@@ -221,7 +222,7 @@ static void python_countermeasures(struct device_node *dev, | |||
221 | /* Python's register file is 1 MB in size. */ | 222 | /* Python's register file is 1 MB in size. */ |
222 | chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), 0x100000); | 223 | chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), 0x100000); |
223 | 224 | ||
224 | /* | 225 | /* |
225 | * Firmware doesn't always clear this bit which is critical | 226 | * Firmware doesn't always clear this bit which is critical |
226 | * for good performance - Anton | 227 | * for good performance - Anton |
227 | */ | 228 | */ |
@@ -292,7 +293,7 @@ static int phb_set_bus_ranges(struct device_node *dev, | |||
292 | if (bus_range == NULL || len < 2 * sizeof(int)) { | 293 | if (bus_range == NULL || len < 2 * sizeof(int)) { |
293 | return 1; | 294 | return 1; |
294 | } | 295 | } |
295 | 296 | ||
296 | phb->first_busno = bus_range[0]; | 297 | phb->first_busno = bus_range[0]; |
297 | phb->last_busno = bus_range[1]; | 298 | phb->last_busno = bus_range[1]; |
298 | 299 | ||
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index e22856ecb5a0..bae4bff138f1 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <asm/io.h> | 33 | #include <asm/io.h> |
34 | #include <asm/prom.h> | 34 | #include <asm/prom.h> |
35 | #include <asm/processor.h> | 35 | #include <asm/processor.h> |
36 | #include <asm/systemcfg.h> | ||
36 | #include <asm/pgtable.h> | 37 | #include <asm/pgtable.h> |
37 | #include <asm/smp.h> | 38 | #include <asm/smp.h> |
38 | #include <asm/elf.h> | 39 | #include <asm/elf.h> |
@@ -51,6 +52,9 @@ | |||
51 | #include <asm/page.h> | 52 | #include <asm/page.h> |
52 | #include <asm/mmu.h> | 53 | #include <asm/mmu.h> |
53 | #include <asm/lmb.h> | 54 | #include <asm/lmb.h> |
55 | #include <asm/xmon.h> | ||
56 | |||
57 | #include "setup.h" | ||
54 | 58 | ||
55 | #undef DEBUG | 59 | #undef DEBUG |
56 | 60 | ||
@@ -60,6 +64,13 @@ | |||
60 | #define DBG(fmt...) | 64 | #define DBG(fmt...) |
61 | #endif | 65 | #endif |
62 | 66 | ||
67 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
68 | int _machine = 0; | ||
69 | EXPORT_SYMBOL(_machine); | ||
70 | #endif | ||
71 | |||
72 | unsigned long klimit = (unsigned long) _end; | ||
73 | |||
63 | /* | 74 | /* |
64 | * This still seems to be needed... -- paulus | 75 | * This still seems to be needed... -- paulus |
65 | */ | 76 | */ |
@@ -510,8 +521,8 @@ void __init smp_setup_cpu_maps(void) | |||
510 | * On pSeries LPAR, we need to know how many cpus | 521 | * On pSeries LPAR, we need to know how many cpus |
511 | * could possibly be added to this partition. | 522 | * could possibly be added to this partition. |
512 | */ | 523 | */ |
513 | if (systemcfg->platform == PLATFORM_PSERIES_LPAR && | 524 | if (_machine == PLATFORM_PSERIES_LPAR && |
514 | (dn = of_find_node_by_path("/rtas"))) { | 525 | (dn = of_find_node_by_path("/rtas"))) { |
515 | int num_addr_cell, num_size_cell, maxcpus; | 526 | int num_addr_cell, num_size_cell, maxcpus; |
516 | unsigned int *ireg; | 527 | unsigned int *ireg; |
517 | 528 | ||
@@ -555,7 +566,27 @@ void __init smp_setup_cpu_maps(void) | |||
555 | cpu_set(cpu ^ 0x1, cpu_sibling_map[cpu]); | 566 | cpu_set(cpu ^ 0x1, cpu_sibling_map[cpu]); |
556 | } | 567 | } |
557 | 568 | ||
558 | systemcfg->processorCount = num_present_cpus(); | 569 | _systemcfg->processorCount = num_present_cpus(); |
559 | #endif /* CONFIG_PPC64 */ | 570 | #endif /* CONFIG_PPC64 */ |
560 | } | 571 | } |
561 | #endif /* CONFIG_SMP */ | 572 | #endif /* CONFIG_SMP */ |
573 | |||
574 | #ifdef CONFIG_XMON | ||
575 | static int __init early_xmon(char *p) | ||
576 | { | ||
577 | /* ensure xmon is enabled */ | ||
578 | if (p) { | ||
579 | if (strncmp(p, "on", 2) == 0) | ||
580 | xmon_init(1); | ||
581 | if (strncmp(p, "off", 3) == 0) | ||
582 | xmon_init(0); | ||
583 | if (strncmp(p, "early", 5) != 0) | ||
584 | return 0; | ||
585 | } | ||
586 | xmon_init(1); | ||
587 | debugger(NULL); | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | early_param("xmon", early_xmon); | ||
592 | #endif | ||
diff --git a/arch/powerpc/kernel/setup.h b/arch/powerpc/kernel/setup.h new file mode 100644 index 000000000000..2ebba755272e --- /dev/null +++ b/arch/powerpc/kernel/setup.h | |||
@@ -0,0 +1,6 @@ | |||
1 | #ifndef _POWERPC_KERNEL_SETUP_H | ||
2 | #define _POWERPC_KERNEL_SETUP_H | ||
3 | |||
4 | void check_for_initrd(void); | ||
5 | |||
6 | #endif /* _POWERPC_KERNEL_SETUP_H */ | ||
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 3af2631e3fab..c98cfcc9cd9a 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c | |||
@@ -40,6 +40,8 @@ | |||
40 | #include <asm/xmon.h> | 40 | #include <asm/xmon.h> |
41 | #include <asm/time.h> | 41 | #include <asm/time.h> |
42 | 42 | ||
43 | #include "setup.h" | ||
44 | |||
43 | #define DBG(fmt...) | 45 | #define DBG(fmt...) |
44 | 46 | ||
45 | #if defined CONFIG_KGDB | 47 | #if defined CONFIG_KGDB |
@@ -70,8 +72,6 @@ unsigned int DMA_MODE_WRITE; | |||
70 | int have_of = 1; | 72 | int have_of = 1; |
71 | 73 | ||
72 | #ifdef CONFIG_PPC_MULTIPLATFORM | 74 | #ifdef CONFIG_PPC_MULTIPLATFORM |
73 | int _machine = 0; | ||
74 | |||
75 | extern void prep_init(void); | 75 | extern void prep_init(void); |
76 | extern void pmac_init(void); | 76 | extern void pmac_init(void); |
77 | extern void chrp_init(void); | 77 | extern void chrp_init(void); |
@@ -279,7 +279,6 @@ arch_initcall(ppc_init); | |||
279 | /* Warning, IO base is not yet inited */ | 279 | /* Warning, IO base is not yet inited */ |
280 | void __init setup_arch(char **cmdline_p) | 280 | void __init setup_arch(char **cmdline_p) |
281 | { | 281 | { |
282 | extern char *klimit; | ||
283 | extern void do_init_bootmem(void); | 282 | extern void do_init_bootmem(void); |
284 | 283 | ||
285 | /* so udelay does something sensible, assume <= 1000 bogomips */ | 284 | /* so udelay does something sensible, assume <= 1000 bogomips */ |
@@ -303,14 +302,9 @@ void __init setup_arch(char **cmdline_p) | |||
303 | pmac_feature_init(); /* New cool way */ | 302 | pmac_feature_init(); /* New cool way */ |
304 | #endif | 303 | #endif |
305 | 304 | ||
306 | #ifdef CONFIG_XMON | 305 | #ifdef CONFIG_XMON_DEFAULT |
307 | xmon_map_scc(); | 306 | xmon_init(1); |
308 | if (strstr(cmd_line, "xmon")) { | 307 | #endif |
309 | xmon_init(1); | ||
310 | debugger(NULL); | ||
311 | } | ||
312 | #endif /* CONFIG_XMON */ | ||
313 | if ( ppc_md.progress ) ppc_md.progress("setup_arch: enter", 0x3eab); | ||
314 | 308 | ||
315 | #if defined(CONFIG_KGDB) | 309 | #if defined(CONFIG_KGDB) |
316 | if (ppc_md.kgdb_map_scc) | 310 | if (ppc_md.kgdb_map_scc) |
@@ -343,7 +337,7 @@ void __init setup_arch(char **cmdline_p) | |||
343 | init_mm.start_code = PAGE_OFFSET; | 337 | init_mm.start_code = PAGE_OFFSET; |
344 | init_mm.end_code = (unsigned long) _etext; | 338 | init_mm.end_code = (unsigned long) _etext; |
345 | init_mm.end_data = (unsigned long) _edata; | 339 | init_mm.end_data = (unsigned long) _edata; |
346 | init_mm.brk = (unsigned long) klimit; | 340 | init_mm.brk = klimit; |
347 | 341 | ||
348 | /* Save unparsed command line copy for /proc/cmdline */ | 342 | /* Save unparsed command line copy for /proc/cmdline */ |
349 | strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); | 343 | strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); |
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 0471e843b6c5..6791668213e7 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c | |||
@@ -61,6 +61,8 @@ | |||
61 | #include <asm/xmon.h> | 61 | #include <asm/xmon.h> |
62 | #include <asm/udbg.h> | 62 | #include <asm/udbg.h> |
63 | 63 | ||
64 | #include "setup.h" | ||
65 | |||
64 | #ifdef DEBUG | 66 | #ifdef DEBUG |
65 | #define DBG(fmt...) udbg_printf(fmt) | 67 | #define DBG(fmt...) udbg_printf(fmt) |
66 | #else | 68 | #else |
@@ -94,15 +96,6 @@ extern void udbg_init_maple_realmode(void); | |||
94 | do { udbg_putc = call_rtas_display_status_delay; } while(0) | 96 | do { udbg_putc = call_rtas_display_status_delay; } while(0) |
95 | #endif | 97 | #endif |
96 | 98 | ||
97 | /* extern void *stab; */ | ||
98 | extern unsigned long klimit; | ||
99 | |||
100 | extern void mm_init_ppc64(void); | ||
101 | extern void stab_initialize(unsigned long stab); | ||
102 | extern void htab_initialize(void); | ||
103 | extern void early_init_devtree(void *flat_dt); | ||
104 | extern void unflatten_device_tree(void); | ||
105 | |||
106 | int have_of = 1; | 99 | int have_of = 1; |
107 | int boot_cpuid = 0; | 100 | int boot_cpuid = 0; |
108 | int boot_cpuid_phys = 0; | 101 | int boot_cpuid_phys = 0; |
@@ -254,11 +247,10 @@ void __init early_setup(unsigned long dt_ptr) | |||
254 | * Iterate all ppc_md structures until we find the proper | 247 | * Iterate all ppc_md structures until we find the proper |
255 | * one for the current machine type | 248 | * one for the current machine type |
256 | */ | 249 | */ |
257 | DBG("Probing machine type for platform %x...\n", | 250 | DBG("Probing machine type for platform %x...\n", _machine); |
258 | systemcfg->platform); | ||
259 | 251 | ||
260 | for (mach = machines; *mach; mach++) { | 252 | for (mach = machines; *mach; mach++) { |
261 | if ((*mach)->probe(systemcfg->platform)) | 253 | if ((*mach)->probe(_machine)) |
262 | break; | 254 | break; |
263 | } | 255 | } |
264 | /* What can we do if we didn't find ? */ | 256 | /* What can we do if we didn't find ? */ |
@@ -290,6 +282,28 @@ void __init early_setup(unsigned long dt_ptr) | |||
290 | DBG(" <- early_setup()\n"); | 282 | DBG(" <- early_setup()\n"); |
291 | } | 283 | } |
292 | 284 | ||
285 | #ifdef CONFIG_SMP | ||
286 | void early_setup_secondary(void) | ||
287 | { | ||
288 | struct paca_struct *lpaca = get_paca(); | ||
289 | |||
290 | /* Mark enabled in PACA */ | ||
291 | lpaca->proc_enabled = 0; | ||
292 | |||
293 | /* Initialize hash table for that CPU */ | ||
294 | htab_initialize_secondary(); | ||
295 | |||
296 | /* Initialize STAB/SLB. We use a virtual address as it works | ||
297 | * in real mode on pSeries and we want a virutal address on | ||
298 | * iSeries anyway | ||
299 | */ | ||
300 | if (cpu_has_feature(CPU_FTR_SLB)) | ||
301 | slb_initialize(); | ||
302 | else | ||
303 | stab_initialize(lpaca->stab_addr); | ||
304 | } | ||
305 | |||
306 | #endif /* CONFIG_SMP */ | ||
293 | 307 | ||
294 | #if defined(CONFIG_SMP) || defined(CONFIG_KEXEC) | 308 | #if defined(CONFIG_SMP) || defined(CONFIG_KEXEC) |
295 | void smp_release_cpus(void) | 309 | void smp_release_cpus(void) |
@@ -315,7 +329,8 @@ void smp_release_cpus(void) | |||
315 | #endif /* CONFIG_SMP || CONFIG_KEXEC */ | 329 | #endif /* CONFIG_SMP || CONFIG_KEXEC */ |
316 | 330 | ||
317 | /* | 331 | /* |
318 | * Initialize some remaining members of the ppc64_caches and systemcfg structures | 332 | * Initialize some remaining members of the ppc64_caches and systemcfg |
333 | * structures | ||
319 | * (at least until we get rid of them completely). This is mostly some | 334 | * (at least until we get rid of them completely). This is mostly some |
320 | * cache informations about the CPU that will be used by cache flush | 335 | * cache informations about the CPU that will be used by cache flush |
321 | * routines and/or provided to userland | 336 | * routines and/or provided to userland |
@@ -340,7 +355,7 @@ static void __init initialize_cache_info(void) | |||
340 | const char *dc, *ic; | 355 | const char *dc, *ic; |
341 | 356 | ||
342 | /* Then read cache informations */ | 357 | /* Then read cache informations */ |
343 | if (systemcfg->platform == PLATFORM_POWERMAC) { | 358 | if (_machine == PLATFORM_POWERMAC) { |
344 | dc = "d-cache-block-size"; | 359 | dc = "d-cache-block-size"; |
345 | ic = "i-cache-block-size"; | 360 | ic = "i-cache-block-size"; |
346 | } else { | 361 | } else { |
@@ -360,8 +375,8 @@ static void __init initialize_cache_info(void) | |||
360 | DBG("Argh, can't find dcache properties ! " | 375 | DBG("Argh, can't find dcache properties ! " |
361 | "sizep: %p, lsizep: %p\n", sizep, lsizep); | 376 | "sizep: %p, lsizep: %p\n", sizep, lsizep); |
362 | 377 | ||
363 | systemcfg->dcache_size = ppc64_caches.dsize = size; | 378 | _systemcfg->dcache_size = ppc64_caches.dsize = size; |
364 | systemcfg->dcache_line_size = | 379 | _systemcfg->dcache_line_size = |
365 | ppc64_caches.dline_size = lsize; | 380 | ppc64_caches.dline_size = lsize; |
366 | ppc64_caches.log_dline_size = __ilog2(lsize); | 381 | ppc64_caches.log_dline_size = __ilog2(lsize); |
367 | ppc64_caches.dlines_per_page = PAGE_SIZE / lsize; | 382 | ppc64_caches.dlines_per_page = PAGE_SIZE / lsize; |
@@ -378,8 +393,8 @@ static void __init initialize_cache_info(void) | |||
378 | DBG("Argh, can't find icache properties ! " | 393 | DBG("Argh, can't find icache properties ! " |
379 | "sizep: %p, lsizep: %p\n", sizep, lsizep); | 394 | "sizep: %p, lsizep: %p\n", sizep, lsizep); |
380 | 395 | ||
381 | systemcfg->icache_size = ppc64_caches.isize = size; | 396 | _systemcfg->icache_size = ppc64_caches.isize = size; |
382 | systemcfg->icache_line_size = | 397 | _systemcfg->icache_line_size = |
383 | ppc64_caches.iline_size = lsize; | 398 | ppc64_caches.iline_size = lsize; |
384 | ppc64_caches.log_iline_size = __ilog2(lsize); | 399 | ppc64_caches.log_iline_size = __ilog2(lsize); |
385 | ppc64_caches.ilines_per_page = PAGE_SIZE / lsize; | 400 | ppc64_caches.ilines_per_page = PAGE_SIZE / lsize; |
@@ -387,10 +402,12 @@ static void __init initialize_cache_info(void) | |||
387 | } | 402 | } |
388 | 403 | ||
389 | /* Add an eye catcher and the systemcfg layout version number */ | 404 | /* Add an eye catcher and the systemcfg layout version number */ |
390 | strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64"); | 405 | strcpy(_systemcfg->eye_catcher, "SYSTEMCFG:PPC64"); |
391 | systemcfg->version.major = SYSTEMCFG_MAJOR; | 406 | _systemcfg->version.major = SYSTEMCFG_MAJOR; |
392 | systemcfg->version.minor = SYSTEMCFG_MINOR; | 407 | _systemcfg->version.minor = SYSTEMCFG_MINOR; |
393 | systemcfg->processor = mfspr(SPRN_PVR); | 408 | _systemcfg->processor = mfspr(SPRN_PVR); |
409 | _systemcfg->platform = _machine; | ||
410 | _systemcfg->physicalMemorySize = lmb_phys_mem_size(); | ||
394 | 411 | ||
395 | DBG(" <- initialize_cache_info()\n"); | 412 | DBG(" <- initialize_cache_info()\n"); |
396 | } | 413 | } |
@@ -479,10 +496,10 @@ void __init setup_system(void) | |||
479 | printk("-----------------------------------------------------\n"); | 496 | printk("-----------------------------------------------------\n"); |
480 | printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size); | 497 | printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size); |
481 | printk("ppc64_interrupt_controller = 0x%ld\n", ppc64_interrupt_controller); | 498 | printk("ppc64_interrupt_controller = 0x%ld\n", ppc64_interrupt_controller); |
482 | printk("systemcfg = 0x%p\n", systemcfg); | 499 | printk("systemcfg = 0x%p\n", _systemcfg); |
483 | printk("systemcfg->platform = 0x%x\n", systemcfg->platform); | 500 | printk("systemcfg->platform = 0x%x\n", _systemcfg->platform); |
484 | printk("systemcfg->processorCount = 0x%lx\n", systemcfg->processorCount); | 501 | printk("systemcfg->processorCount = 0x%lx\n", _systemcfg->processorCount); |
485 | printk("systemcfg->physicalMemorySize = 0x%lx\n", systemcfg->physicalMemorySize); | 502 | printk("systemcfg->physicalMemorySize = 0x%lx\n", _systemcfg->physicalMemorySize); |
486 | printk("ppc64_caches.dcache_line_size = 0x%x\n", | 503 | printk("ppc64_caches.dcache_line_size = 0x%x\n", |
487 | ppc64_caches.dline_size); | 504 | ppc64_caches.dline_size); |
488 | printk("ppc64_caches.icache_line_size = 0x%x\n", | 505 | printk("ppc64_caches.icache_line_size = 0x%x\n", |
@@ -564,12 +581,12 @@ void __init setup_syscall_map(void) | |||
564 | for (i = 0; i < __NR_syscalls; i++) { | 581 | for (i = 0; i < __NR_syscalls; i++) { |
565 | if (sys_call_table[i*2] != sys_ni_syscall) { | 582 | if (sys_call_table[i*2] != sys_ni_syscall) { |
566 | count64++; | 583 | count64++; |
567 | systemcfg->syscall_map_64[i >> 5] |= | 584 | _systemcfg->syscall_map_64[i >> 5] |= |
568 | 0x80000000UL >> (i & 0x1f); | 585 | 0x80000000UL >> (i & 0x1f); |
569 | } | 586 | } |
570 | if (sys_call_table[i*2+1] != sys_ni_syscall) { | 587 | if (sys_call_table[i*2+1] != sys_ni_syscall) { |
571 | count32++; | 588 | count32++; |
572 | systemcfg->syscall_map_32[i >> 5] |= | 589 | _systemcfg->syscall_map_32[i >> 5] |= |
573 | 0x80000000UL >> (i & 0x1f); | 590 | 0x80000000UL >> (i & 0x1f); |
574 | } | 591 | } |
575 | } | 592 | } |
@@ -858,26 +875,6 @@ int check_legacy_ioport(unsigned long base_port) | |||
858 | } | 875 | } |
859 | EXPORT_SYMBOL(check_legacy_ioport); | 876 | EXPORT_SYMBOL(check_legacy_ioport); |
860 | 877 | ||
861 | #ifdef CONFIG_XMON | ||
862 | static int __init early_xmon(char *p) | ||
863 | { | ||
864 | /* ensure xmon is enabled */ | ||
865 | if (p) { | ||
866 | if (strncmp(p, "on", 2) == 0) | ||
867 | xmon_init(1); | ||
868 | if (strncmp(p, "off", 3) == 0) | ||
869 | xmon_init(0); | ||
870 | if (strncmp(p, "early", 5) != 0) | ||
871 | return 0; | ||
872 | } | ||
873 | xmon_init(1); | ||
874 | debugger(NULL); | ||
875 | |||
876 | return 0; | ||
877 | } | ||
878 | early_param("xmon", early_xmon); | ||
879 | #endif | ||
880 | |||
881 | void cpu_die(void) | 878 | void cpu_die(void) |
882 | { | 879 | { |
883 | if (ppc_md.cpu_die) | 880 | if (ppc_md.cpu_die) |
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 081d931eae48..a7c4515f320f 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c | |||
@@ -42,6 +42,7 @@ | |||
42 | 42 | ||
43 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
44 | #include <asm/cacheflush.h> | 44 | #include <asm/cacheflush.h> |
45 | #include <asm/sigcontext.h> | ||
45 | #ifdef CONFIG_PPC64 | 46 | #ifdef CONFIG_PPC64 |
46 | #include "ppc32.h" | 47 | #include "ppc32.h" |
47 | #include <asm/unistd.h> | 48 | #include <asm/unistd.h> |
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 5c330c3366e4..e28a139c29d0 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <asm/cputable.h> | 44 | #include <asm/cputable.h> |
45 | #include <asm/system.h> | 45 | #include <asm/system.h> |
46 | #include <asm/mpic.h> | 46 | #include <asm/mpic.h> |
47 | #include <asm/systemcfg.h> | ||
47 | #ifdef CONFIG_PPC64 | 48 | #ifdef CONFIG_PPC64 |
48 | #include <asm/paca.h> | 49 | #include <asm/paca.h> |
49 | #endif | 50 | #endif |
@@ -368,9 +369,11 @@ int generic_cpu_disable(void) | |||
368 | if (cpu == boot_cpuid) | 369 | if (cpu == boot_cpuid) |
369 | return -EBUSY; | 370 | return -EBUSY; |
370 | 371 | ||
371 | systemcfg->processorCount--; | ||
372 | cpu_clear(cpu, cpu_online_map); | 372 | cpu_clear(cpu, cpu_online_map); |
373 | #ifdef CONFIG_PPC64 | ||
374 | _systemcfg->processorCount--; | ||
373 | fixup_irqs(cpu_online_map); | 375 | fixup_irqs(cpu_online_map); |
376 | #endif | ||
374 | return 0; | 377 | return 0; |
375 | } | 378 | } |
376 | 379 | ||
@@ -388,9 +391,11 @@ int generic_cpu_enable(unsigned int cpu) | |||
388 | while (!cpu_online(cpu)) | 391 | while (!cpu_online(cpu)) |
389 | cpu_relax(); | 392 | cpu_relax(); |
390 | 393 | ||
394 | #ifdef CONFIG_PPC64 | ||
391 | fixup_irqs(cpu_online_map); | 395 | fixup_irqs(cpu_online_map); |
392 | /* counter the irq disable in fixup_irqs */ | 396 | /* counter the irq disable in fixup_irqs */ |
393 | local_irq_enable(); | 397 | local_irq_enable(); |
398 | #endif | ||
394 | return 0; | 399 | return 0; |
395 | } | 400 | } |
396 | 401 | ||
@@ -419,7 +424,9 @@ void generic_mach_cpu_die(void) | |||
419 | while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE) | 424 | while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE) |
420 | cpu_relax(); | 425 | cpu_relax(); |
421 | 426 | ||
427 | #ifdef CONFIG_PPC64 | ||
422 | flush_tlb_pending(); | 428 | flush_tlb_pending(); |
429 | #endif | ||
423 | cpu_set(cpu, cpu_online_map); | 430 | cpu_set(cpu, cpu_online_map); |
424 | local_irq_enable(); | 431 | local_irq_enable(); |
425 | } | 432 | } |
@@ -510,6 +517,7 @@ int __devinit start_secondary(void *unused) | |||
510 | 517 | ||
511 | smp_store_cpu_info(cpu); | 518 | smp_store_cpu_info(cpu); |
512 | set_dec(tb_ticks_per_jiffy); | 519 | set_dec(tb_ticks_per_jiffy); |
520 | preempt_disable(); | ||
513 | cpu_callin_map[cpu] = 1; | 521 | cpu_callin_map[cpu] = 1; |
514 | 522 | ||
515 | smp_ops->setup_cpu(cpu); | 523 | smp_ops->setup_cpu(cpu); |
diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c index a8210ed5c686..9c921d1c4084 100644 --- a/arch/powerpc/kernel/sys_ppc32.c +++ b/arch/powerpc/kernel/sys_ppc32.c | |||
@@ -52,7 +52,6 @@ | |||
52 | #include <asm/semaphore.h> | 52 | #include <asm/semaphore.h> |
53 | #include <asm/time.h> | 53 | #include <asm/time.h> |
54 | #include <asm/mmu_context.h> | 54 | #include <asm/mmu_context.h> |
55 | #include <asm/systemcfg.h> | ||
56 | #include <asm/ppc-pci.h> | 55 | #include <asm/ppc-pci.h> |
57 | 56 | ||
58 | /* readdir & getdents */ | 57 | /* readdir & getdents */ |
diff --git a/arch/ppc64/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index e99ec62c2c52..850af198fb5f 100644 --- a/arch/ppc64/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c | |||
@@ -232,7 +232,7 @@ static void register_cpu_online(unsigned int cpu) | |||
232 | sysdev_create_file(s, &attr_pmc7); | 232 | sysdev_create_file(s, &attr_pmc7); |
233 | if (cur_cpu_spec->num_pmcs >= 8) | 233 | if (cur_cpu_spec->num_pmcs >= 8) |
234 | sysdev_create_file(s, &attr_pmc8); | 234 | sysdev_create_file(s, &attr_pmc8); |
235 | 235 | ||
236 | if (cpu_has_feature(CPU_FTR_SMT)) | 236 | if (cpu_has_feature(CPU_FTR_SMT)) |
237 | sysdev_create_file(s, &attr_purr); | 237 | sysdev_create_file(s, &attr_purr); |
238 | } | 238 | } |
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index a6282b625b44..260b6ecd26a9 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c | |||
@@ -271,13 +271,13 @@ static inline void update_gtod(u64 new_tb_stamp, u64 new_stamp_xsec, | |||
271 | * tb_to_xs and stamp_xsec values are consistent. If not, then it | 271 | * tb_to_xs and stamp_xsec values are consistent. If not, then it |
272 | * loops back and reads them again until this criteria is met. | 272 | * loops back and reads them again until this criteria is met. |
273 | */ | 273 | */ |
274 | ++(systemcfg->tb_update_count); | 274 | ++(_systemcfg->tb_update_count); |
275 | smp_wmb(); | 275 | smp_wmb(); |
276 | systemcfg->tb_orig_stamp = new_tb_stamp; | 276 | _systemcfg->tb_orig_stamp = new_tb_stamp; |
277 | systemcfg->stamp_xsec = new_stamp_xsec; | 277 | _systemcfg->stamp_xsec = new_stamp_xsec; |
278 | systemcfg->tb_to_xs = new_tb_to_xs; | 278 | _systemcfg->tb_to_xs = new_tb_to_xs; |
279 | smp_wmb(); | 279 | smp_wmb(); |
280 | ++(systemcfg->tb_update_count); | 280 | ++(_systemcfg->tb_update_count); |
281 | #endif | 281 | #endif |
282 | } | 282 | } |
283 | 283 | ||
@@ -357,8 +357,9 @@ static void iSeries_tb_recal(void) | |||
357 | do_gtod.tb_ticks_per_sec = tb_ticks_per_sec; | 357 | do_gtod.tb_ticks_per_sec = tb_ticks_per_sec; |
358 | tb_to_xs = divres.result_low; | 358 | tb_to_xs = divres.result_low; |
359 | do_gtod.varp->tb_to_xs = tb_to_xs; | 359 | do_gtod.varp->tb_to_xs = tb_to_xs; |
360 | systemcfg->tb_ticks_per_sec = tb_ticks_per_sec; | 360 | _systemcfg->tb_ticks_per_sec = |
361 | systemcfg->tb_to_xs = tb_to_xs; | 361 | tb_ticks_per_sec; |
362 | _systemcfg->tb_to_xs = tb_to_xs; | ||
362 | } | 363 | } |
363 | else { | 364 | else { |
364 | printk( "Titan recalibrate: FAILED (difference > 4 percent)\n" | 365 | printk( "Titan recalibrate: FAILED (difference > 4 percent)\n" |
@@ -483,6 +484,8 @@ void __init smp_space_timers(unsigned int max_cpus) | |||
483 | unsigned long offset = tb_ticks_per_jiffy / max_cpus; | 484 | unsigned long offset = tb_ticks_per_jiffy / max_cpus; |
484 | unsigned long previous_tb = per_cpu(last_jiffy, boot_cpuid); | 485 | unsigned long previous_tb = per_cpu(last_jiffy, boot_cpuid); |
485 | 486 | ||
487 | /* make sure tb > per_cpu(last_jiffy, cpu) for all cpus always */ | ||
488 | previous_tb -= tb_ticks_per_jiffy; | ||
486 | for_each_cpu(i) { | 489 | for_each_cpu(i) { |
487 | if (i != boot_cpuid) { | 490 | if (i != boot_cpuid) { |
488 | previous_tb += offset; | 491 | previous_tb += offset; |
@@ -559,8 +562,8 @@ int do_settimeofday(struct timespec *tv) | |||
559 | update_gtod(tb_last_jiffy, new_xsec, do_gtod.varp->tb_to_xs); | 562 | update_gtod(tb_last_jiffy, new_xsec, do_gtod.varp->tb_to_xs); |
560 | 563 | ||
561 | #ifdef CONFIG_PPC64 | 564 | #ifdef CONFIG_PPC64 |
562 | systemcfg->tz_minuteswest = sys_tz.tz_minuteswest; | 565 | _systemcfg->tz_minuteswest = sys_tz.tz_minuteswest; |
563 | systemcfg->tz_dsttime = sys_tz.tz_dsttime; | 566 | _systemcfg->tz_dsttime = sys_tz.tz_dsttime; |
564 | #endif | 567 | #endif |
565 | 568 | ||
566 | write_sequnlock_irqrestore(&xtime_lock, flags); | 569 | write_sequnlock_irqrestore(&xtime_lock, flags); |
@@ -711,11 +714,11 @@ void __init time_init(void) | |||
711 | do_gtod.varp->tb_to_xs = tb_to_xs; | 714 | do_gtod.varp->tb_to_xs = tb_to_xs; |
712 | do_gtod.tb_to_us = tb_to_us; | 715 | do_gtod.tb_to_us = tb_to_us; |
713 | #ifdef CONFIG_PPC64 | 716 | #ifdef CONFIG_PPC64 |
714 | systemcfg->tb_orig_stamp = tb_last_jiffy; | 717 | _systemcfg->tb_orig_stamp = tb_last_jiffy; |
715 | systemcfg->tb_update_count = 0; | 718 | _systemcfg->tb_update_count = 0; |
716 | systemcfg->tb_ticks_per_sec = tb_ticks_per_sec; | 719 | _systemcfg->tb_ticks_per_sec = tb_ticks_per_sec; |
717 | systemcfg->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC; | 720 | _systemcfg->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC; |
718 | systemcfg->tb_to_xs = tb_to_xs; | 721 | _systemcfg->tb_to_xs = tb_to_xs; |
719 | #endif | 722 | #endif |
720 | 723 | ||
721 | time_freq = 0; | 724 | time_freq = 0; |
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 0578f8387603..2020bb7648fb 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
@@ -129,7 +129,7 @@ int die(const char *str, struct pt_regs *regs, long err) | |||
129 | nl = 1; | 129 | nl = 1; |
130 | #endif | 130 | #endif |
131 | #ifdef CONFIG_PPC64 | 131 | #ifdef CONFIG_PPC64 |
132 | switch (systemcfg->platform) { | 132 | switch (_machine) { |
133 | case PLATFORM_PSERIES: | 133 | case PLATFORM_PSERIES: |
134 | printk("PSERIES "); | 134 | printk("PSERIES "); |
135 | nl = 1; | 135 | nl = 1; |
diff --git a/arch/powerpc/lib/bitops.c b/arch/powerpc/lib/bitops.c index b67ce3004ebf..f68ad71a0187 100644 --- a/arch/powerpc/lib/bitops.c +++ b/arch/powerpc/lib/bitops.c | |||
@@ -41,7 +41,7 @@ unsigned long find_next_bit(const unsigned long *addr, unsigned long size, | |||
41 | tmp = *p; | 41 | tmp = *p; |
42 | 42 | ||
43 | found_first: | 43 | found_first: |
44 | tmp &= (~0UL >> (64 - size)); | 44 | tmp &= (~0UL >> (BITS_PER_LONG - size)); |
45 | if (tmp == 0UL) /* Are any bits set? */ | 45 | if (tmp == 0UL) /* Are any bits set? */ |
46 | return result + size; /* Nope. */ | 46 | return result + size; /* Nope. */ |
47 | found_middle: | 47 | found_middle: |
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 22e474876133..706e8a63ced9 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c | |||
@@ -84,10 +84,11 @@ | |||
84 | extern unsigned long dart_tablebase; | 84 | extern unsigned long dart_tablebase; |
85 | #endif /* CONFIG_U3_DART */ | 85 | #endif /* CONFIG_U3_DART */ |
86 | 86 | ||
87 | static unsigned long _SDR1; | ||
88 | struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT]; | ||
89 | |||
87 | hpte_t *htab_address; | 90 | hpte_t *htab_address; |
88 | unsigned long htab_hash_mask; | 91 | unsigned long htab_hash_mask; |
89 | unsigned long _SDR1; | ||
90 | struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT]; | ||
91 | int mmu_linear_psize = MMU_PAGE_4K; | 92 | int mmu_linear_psize = MMU_PAGE_4K; |
92 | int mmu_virtual_psize = MMU_PAGE_4K; | 93 | int mmu_virtual_psize = MMU_PAGE_4K; |
93 | #ifdef CONFIG_HUGETLB_PAGE | 94 | #ifdef CONFIG_HUGETLB_PAGE |
@@ -165,7 +166,7 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend, | |||
165 | * normal insert callback here. | 166 | * normal insert callback here. |
166 | */ | 167 | */ |
167 | #ifdef CONFIG_PPC_ISERIES | 168 | #ifdef CONFIG_PPC_ISERIES |
168 | if (systemcfg->platform == PLATFORM_ISERIES_LPAR) | 169 | if (_machine == PLATFORM_ISERIES_LPAR) |
169 | ret = iSeries_hpte_insert(hpteg, va, | 170 | ret = iSeries_hpte_insert(hpteg, va, |
170 | virt_to_abs(paddr), | 171 | virt_to_abs(paddr), |
171 | tmp_mode, | 172 | tmp_mode, |
@@ -174,7 +175,7 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend, | |||
174 | else | 175 | else |
175 | #endif | 176 | #endif |
176 | #ifdef CONFIG_PPC_PSERIES | 177 | #ifdef CONFIG_PPC_PSERIES |
177 | if (systemcfg->platform & PLATFORM_LPAR) | 178 | if (_machine & PLATFORM_LPAR) |
178 | ret = pSeries_lpar_hpte_insert(hpteg, va, | 179 | ret = pSeries_lpar_hpte_insert(hpteg, va, |
179 | virt_to_abs(paddr), | 180 | virt_to_abs(paddr), |
180 | tmp_mode, | 181 | tmp_mode, |
@@ -293,7 +294,7 @@ static void __init htab_init_page_sizes(void) | |||
293 | * Not in the device-tree, let's fallback on known size | 294 | * Not in the device-tree, let's fallback on known size |
294 | * list for 16M capable GP & GR | 295 | * list for 16M capable GP & GR |
295 | */ | 296 | */ |
296 | if ((systemcfg->platform != PLATFORM_ISERIES_LPAR) && | 297 | if ((_machine != PLATFORM_ISERIES_LPAR) && |
297 | cpu_has_feature(CPU_FTR_16M_PAGE)) | 298 | cpu_has_feature(CPU_FTR_16M_PAGE)) |
298 | memcpy(mmu_psize_defs, mmu_psize_defaults_gp, | 299 | memcpy(mmu_psize_defs, mmu_psize_defaults_gp, |
299 | sizeof(mmu_psize_defaults_gp)); | 300 | sizeof(mmu_psize_defaults_gp)); |
@@ -364,7 +365,7 @@ static int __init htab_dt_scan_pftsize(unsigned long node, | |||
364 | 365 | ||
365 | static unsigned long __init htab_get_table_size(void) | 366 | static unsigned long __init htab_get_table_size(void) |
366 | { | 367 | { |
367 | unsigned long rnd_mem_size, pteg_count; | 368 | unsigned long mem_size, rnd_mem_size, pteg_count; |
368 | 369 | ||
369 | /* If hash size isn't already provided by the platform, we try to | 370 | /* If hash size isn't already provided by the platform, we try to |
370 | * retreive it from the device-tree. If it's not there neither, we | 371 | * retreive it from the device-tree. If it's not there neither, we |
@@ -376,8 +377,9 @@ static unsigned long __init htab_get_table_size(void) | |||
376 | return 1UL << ppc64_pft_size; | 377 | return 1UL << ppc64_pft_size; |
377 | 378 | ||
378 | /* round mem_size up to next power of 2 */ | 379 | /* round mem_size up to next power of 2 */ |
379 | rnd_mem_size = 1UL << __ilog2(systemcfg->physicalMemorySize); | 380 | mem_size = lmb_phys_mem_size(); |
380 | if (rnd_mem_size < systemcfg->physicalMemorySize) | 381 | rnd_mem_size = 1UL << __ilog2(mem_size); |
382 | if (rnd_mem_size < mem_size) | ||
381 | rnd_mem_size <<= 1; | 383 | rnd_mem_size <<= 1; |
382 | 384 | ||
383 | /* # pages / 2 */ | 385 | /* # pages / 2 */ |
@@ -386,6 +388,15 @@ static unsigned long __init htab_get_table_size(void) | |||
386 | return pteg_count << 7; | 388 | return pteg_count << 7; |
387 | } | 389 | } |
388 | 390 | ||
391 | #ifdef CONFIG_MEMORY_HOTPLUG | ||
392 | void create_section_mapping(unsigned long start, unsigned long end) | ||
393 | { | ||
394 | BUG_ON(htab_bolt_mapping(start, end, start, | ||
395 | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_COHERENT | PP_RWXX, | ||
396 | mmu_linear_psize)); | ||
397 | } | ||
398 | #endif /* CONFIG_MEMORY_HOTPLUG */ | ||
399 | |||
389 | void __init htab_initialize(void) | 400 | void __init htab_initialize(void) |
390 | { | 401 | { |
391 | unsigned long table, htab_size_bytes; | 402 | unsigned long table, htab_size_bytes; |
@@ -410,7 +421,7 @@ void __init htab_initialize(void) | |||
410 | 421 | ||
411 | htab_hash_mask = pteg_count - 1; | 422 | htab_hash_mask = pteg_count - 1; |
412 | 423 | ||
413 | if (systemcfg->platform & PLATFORM_LPAR) { | 424 | if (platform_is_lpar()) { |
414 | /* Using a hypervisor which owns the htab */ | 425 | /* Using a hypervisor which owns the htab */ |
415 | htab_address = NULL; | 426 | htab_address = NULL; |
416 | _SDR1 = 0; | 427 | _SDR1 = 0; |
@@ -431,6 +442,9 @@ void __init htab_initialize(void) | |||
431 | 442 | ||
432 | /* Initialize the HPT with no entries */ | 443 | /* Initialize the HPT with no entries */ |
433 | memset((void *)table, 0, htab_size_bytes); | 444 | memset((void *)table, 0, htab_size_bytes); |
445 | |||
446 | /* Set SDR1 */ | ||
447 | mtspr(SPRN_SDR1, _SDR1); | ||
434 | } | 448 | } |
435 | 449 | ||
436 | mode_rw = _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_COHERENT | PP_RWXX; | 450 | mode_rw = _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_COHERENT | PP_RWXX; |
@@ -500,6 +514,12 @@ void __init htab_initialize(void) | |||
500 | #undef KB | 514 | #undef KB |
501 | #undef MB | 515 | #undef MB |
502 | 516 | ||
517 | void __init htab_initialize_secondary(void) | ||
518 | { | ||
519 | if (!platform_is_lpar()) | ||
520 | mtspr(SPRN_SDR1, _SDR1); | ||
521 | } | ||
522 | |||
503 | /* | 523 | /* |
504 | * Called by asm hashtable.S for doing lazy icache flush | 524 | * Called by asm hashtable.S for doing lazy icache flush |
505 | */ | 525 | */ |
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c index 4612a79dfb6e..7d4b8b5f0606 100644 --- a/arch/powerpc/mm/init_32.c +++ b/arch/powerpc/mm/init_32.c | |||
@@ -84,9 +84,6 @@ void MMU_init(void); | |||
84 | /* XXX should be in current.h -- paulus */ | 84 | /* XXX should be in current.h -- paulus */ |
85 | extern struct task_struct *current_set[NR_CPUS]; | 85 | extern struct task_struct *current_set[NR_CPUS]; |
86 | 86 | ||
87 | char *klimit = _end; | ||
88 | struct device_node *memory_node; | ||
89 | |||
90 | extern int init_bootmem_done; | 87 | extern int init_bootmem_done; |
91 | 88 | ||
92 | /* | 89 | /* |
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c index ce974c83d88a..1134f70f231d 100644 --- a/arch/powerpc/mm/init_64.c +++ b/arch/powerpc/mm/init_64.c | |||
@@ -20,6 +20,8 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #undef DEBUG | ||
24 | |||
23 | #include <linux/config.h> | 25 | #include <linux/config.h> |
24 | #include <linux/signal.h> | 26 | #include <linux/signal.h> |
25 | #include <linux/sched.h> | 27 | #include <linux/sched.h> |
@@ -64,6 +66,12 @@ | |||
64 | #include <asm/vdso.h> | 66 | #include <asm/vdso.h> |
65 | #include <asm/imalloc.h> | 67 | #include <asm/imalloc.h> |
66 | 68 | ||
69 | #ifdef DEBUG | ||
70 | #define DBG(fmt...) printk(fmt) | ||
71 | #else | ||
72 | #define DBG(fmt...) | ||
73 | #endif | ||
74 | |||
67 | #if PGTABLE_RANGE > USER_VSID_RANGE | 75 | #if PGTABLE_RANGE > USER_VSID_RANGE |
68 | #warning Limited user VSID range means pagetable space is wasted | 76 | #warning Limited user VSID range means pagetable space is wasted |
69 | #endif | 77 | #endif |
@@ -72,8 +80,6 @@ | |||
72 | #warning TASK_SIZE is smaller than it needs to be. | 80 | #warning TASK_SIZE is smaller than it needs to be. |
73 | #endif | 81 | #endif |
74 | 82 | ||
75 | unsigned long klimit = (unsigned long)_end; | ||
76 | |||
77 | /* max amount of RAM to use */ | 83 | /* max amount of RAM to use */ |
78 | unsigned long __max_memory; | 84 | unsigned long __max_memory; |
79 | 85 | ||
@@ -188,14 +194,14 @@ static void zero_ctor(void *addr, kmem_cache_t *cache, unsigned long flags) | |||
188 | } | 194 | } |
189 | 195 | ||
190 | #ifdef CONFIG_PPC_64K_PAGES | 196 | #ifdef CONFIG_PPC_64K_PAGES |
191 | static const int pgtable_cache_size[2] = { | 197 | static const unsigned int pgtable_cache_size[3] = { |
192 | PTE_TABLE_SIZE, PGD_TABLE_SIZE | 198 | PTE_TABLE_SIZE, PMD_TABLE_SIZE, PGD_TABLE_SIZE |
193 | }; | 199 | }; |
194 | static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = { | 200 | static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = { |
195 | "pte_pmd_cache", "pgd_cache", | 201 | "pte_pmd_cache", "pmd_cache", "pgd_cache", |
196 | }; | 202 | }; |
197 | #else | 203 | #else |
198 | static const int pgtable_cache_size[2] = { | 204 | static const unsigned int pgtable_cache_size[2] = { |
199 | PTE_TABLE_SIZE, PMD_TABLE_SIZE | 205 | PTE_TABLE_SIZE, PMD_TABLE_SIZE |
200 | }; | 206 | }; |
201 | static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = { | 207 | static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = { |
@@ -213,6 +219,8 @@ void pgtable_cache_init(void) | |||
213 | int size = pgtable_cache_size[i]; | 219 | int size = pgtable_cache_size[i]; |
214 | const char *name = pgtable_cache_name[i]; | 220 | const char *name = pgtable_cache_name[i]; |
215 | 221 | ||
222 | DBG("Allocating page table cache %s (#%d) " | ||
223 | "for size: %08x...\n", name, i, size); | ||
216 | pgtable_cache[i] = kmem_cache_create(name, | 224 | pgtable_cache[i] = kmem_cache_create(name, |
217 | size, size, | 225 | size, size, |
218 | SLAB_HWCACHE_ALIGN | | 226 | SLAB_HWCACHE_ALIGN | |
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 6f55efd9be95..1dd3cc69a490 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c | |||
@@ -110,6 +110,7 @@ EXPORT_SYMBOL(phys_mem_access_prot); | |||
110 | void online_page(struct page *page) | 110 | void online_page(struct page *page) |
111 | { | 111 | { |
112 | ClearPageReserved(page); | 112 | ClearPageReserved(page); |
113 | set_page_count(page, 0); | ||
113 | free_cold_page(page); | 114 | free_cold_page(page); |
114 | totalram_pages++; | 115 | totalram_pages++; |
115 | num_physpages++; | 116 | num_physpages++; |
@@ -127,6 +128,9 @@ int __devinit add_memory(u64 start, u64 size) | |||
127 | unsigned long start_pfn = start >> PAGE_SHIFT; | 128 | unsigned long start_pfn = start >> PAGE_SHIFT; |
128 | unsigned long nr_pages = size >> PAGE_SHIFT; | 129 | unsigned long nr_pages = size >> PAGE_SHIFT; |
129 | 130 | ||
131 | start += KERNELBASE; | ||
132 | create_section_mapping(start, start + size); | ||
133 | |||
130 | /* this should work for most non-highmem platforms */ | 134 | /* this should work for most non-highmem platforms */ |
131 | zone = pgdata->node_zones; | 135 | zone = pgdata->node_zones; |
132 | 136 | ||
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index 900842451bd3..c7f7bb6f30b3 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c | |||
@@ -122,8 +122,11 @@ static int map_io_page(unsigned long ea, unsigned long pa, int flags) | |||
122 | * | 122 | * |
123 | */ | 123 | */ |
124 | if (htab_bolt_mapping(ea, ea + PAGE_SIZE, pa, flags, | 124 | if (htab_bolt_mapping(ea, ea + PAGE_SIZE, pa, flags, |
125 | mmu_virtual_psize)) | 125 | mmu_virtual_psize)) { |
126 | panic("Can't map bolted IO mapping"); | 126 | printk(KERN_ERR "Failed to do bolted mapping IO " |
127 | "memory at %016lx !\n", pa); | ||
128 | return -ENOMEM; | ||
129 | } | ||
127 | } | 130 | } |
128 | return 0; | 131 | return 0; |
129 | } | 132 | } |
diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c index fa325dbf98fc..cfbb4e1f966b 100644 --- a/arch/powerpc/mm/stab.c +++ b/arch/powerpc/mm/stab.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <asm/cputable.h> | 20 | #include <asm/cputable.h> |
21 | #include <asm/lmb.h> | 21 | #include <asm/lmb.h> |
22 | #include <asm/abs_addr.h> | 22 | #include <asm/abs_addr.h> |
23 | #include <asm/firmware.h> | ||
23 | 24 | ||
24 | struct stab_entry { | 25 | struct stab_entry { |
25 | unsigned long esid_data; | 26 | unsigned long esid_data; |
@@ -256,7 +257,7 @@ void stabs_alloc(void) | |||
256 | 257 | ||
257 | paca[cpu].stab_addr = newstab; | 258 | paca[cpu].stab_addr = newstab; |
258 | paca[cpu].stab_real = virt_to_abs(newstab); | 259 | paca[cpu].stab_real = virt_to_abs(newstab); |
259 | printk(KERN_DEBUG "Segment table for CPU %d at 0x%lx " | 260 | printk(KERN_INFO "Segment table for CPU %d at 0x%lx " |
260 | "virtual, 0x%lx absolute\n", | 261 | "virtual, 0x%lx absolute\n", |
261 | cpu, paca[cpu].stab_addr, paca[cpu].stab_real); | 262 | cpu, paca[cpu].stab_addr, paca[cpu].stab_real); |
262 | } | 263 | } |
@@ -270,10 +271,28 @@ void stabs_alloc(void) | |||
270 | void stab_initialize(unsigned long stab) | 271 | void stab_initialize(unsigned long stab) |
271 | { | 272 | { |
272 | unsigned long vsid = get_kernel_vsid(KERNELBASE); | 273 | unsigned long vsid = get_kernel_vsid(KERNELBASE); |
274 | unsigned long stabreal; | ||
273 | 275 | ||
274 | asm volatile("isync; slbia; isync":::"memory"); | 276 | asm volatile("isync; slbia; isync":::"memory"); |
275 | make_ste(stab, GET_ESID(KERNELBASE), vsid); | 277 | make_ste(stab, GET_ESID(KERNELBASE), vsid); |
276 | 278 | ||
277 | /* Order update */ | 279 | /* Order update */ |
278 | asm volatile("sync":::"memory"); | 280 | asm volatile("sync":::"memory"); |
281 | |||
282 | /* Set ASR */ | ||
283 | stabreal = get_paca()->stab_real | 0x1ul; | ||
284 | |||
285 | #ifdef CONFIG_PPC_ISERIES | ||
286 | if (firmware_has_feature(FW_FEATURE_ISERIES)) { | ||
287 | HvCall1(HvCallBaseSetASR, stabreal); | ||
288 | return; | ||
289 | } | ||
290 | #endif /* CONFIG_PPC_ISERIES */ | ||
291 | #ifdef CONFIG_PPC_PSERIES | ||
292 | if (platform_is_lpar()) { | ||
293 | plpar_hcall_norets(H_SET_ASR, stabreal); | ||
294 | return; | ||
295 | } | ||
296 | #endif | ||
297 | mtspr(SPRN_ASR, stabreal); | ||
279 | } | 298 | } |
diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c index c4ee5478427b..e3a024e324b6 100644 --- a/arch/powerpc/oprofile/op_model_power4.c +++ b/arch/powerpc/oprofile/op_model_power4.c | |||
@@ -233,8 +233,7 @@ static unsigned long get_pc(struct pt_regs *regs) | |||
233 | mmcra = mfspr(SPRN_MMCRA); | 233 | mmcra = mfspr(SPRN_MMCRA); |
234 | 234 | ||
235 | /* Were we in the hypervisor? */ | 235 | /* Were we in the hypervisor? */ |
236 | if ((systemcfg->platform == PLATFORM_PSERIES_LPAR) && | 236 | if (platform_is_lpar() && (mmcra & MMCRA_SIHV)) |
237 | (mmcra & MMCRA_SIHV)) | ||
238 | /* function descriptor madness */ | 237 | /* function descriptor madness */ |
239 | return *((unsigned long *)hypervisor_bucket); | 238 | return *((unsigned long *)hypervisor_bucket); |
240 | 239 | ||
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index ecd32d5d85f4..4099ddab9205 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c | |||
@@ -361,7 +361,9 @@ static void __init chrp_find_openpic(void) | |||
361 | printk(KERN_INFO "OpenPIC at %lx\n", opaddr); | 361 | printk(KERN_INFO "OpenPIC at %lx\n", opaddr); |
362 | 362 | ||
363 | irq_count = NR_IRQS - NUM_ISA_INTERRUPTS - 4; /* leave room for IPIs */ | 363 | irq_count = NR_IRQS - NUM_ISA_INTERRUPTS - 4; /* leave room for IPIs */ |
364 | prom_get_irq_senses(init_senses, NUM_8259_INTERRUPTS, NR_IRQS - 4); | 364 | prom_get_irq_senses(init_senses, NUM_ISA_INTERRUPTS, NR_IRQS - 4); |
365 | /* i8259 cascade is always positive level */ | ||
366 | init_senses[0] = IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE; | ||
365 | 367 | ||
366 | iranges = (unsigned int *) get_property(np, "interrupt-ranges", &len); | 368 | iranges = (unsigned int *) get_property(np, "interrupt-ranges", &len); |
367 | if (iranges == NULL) | 369 | if (iranges == NULL) |
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index a06603d84a45..01090e9ce0cf 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c | |||
@@ -103,6 +103,9 @@ static void intReceived(struct XmPciLpEvent *eventParm, | |||
103 | struct pt_regs *regsParm) | 103 | struct pt_regs *regsParm) |
104 | { | 104 | { |
105 | int irq; | 105 | int irq; |
106 | #ifdef CONFIG_IRQSTACKS | ||
107 | struct thread_info *curtp, *irqtp; | ||
108 | #endif | ||
106 | 109 | ||
107 | ++Pci_Interrupt_Count; | 110 | ++Pci_Interrupt_Count; |
108 | 111 | ||
@@ -110,7 +113,20 @@ static void intReceived(struct XmPciLpEvent *eventParm, | |||
110 | case XmPciLpEvent_SlotInterrupt: | 113 | case XmPciLpEvent_SlotInterrupt: |
111 | irq = eventParm->hvLpEvent.xCorrelationToken; | 114 | irq = eventParm->hvLpEvent.xCorrelationToken; |
112 | /* Dispatch the interrupt handlers for this irq */ | 115 | /* Dispatch the interrupt handlers for this irq */ |
113 | ppc_irq_dispatch_handler(regsParm, irq); | 116 | #ifdef CONFIG_IRQSTACKS |
117 | /* Switch to the irq stack to handle this */ | ||
118 | curtp = current_thread_info(); | ||
119 | irqtp = hardirq_ctx[smp_processor_id()]; | ||
120 | if (curtp != irqtp) { | ||
121 | irqtp->task = curtp->task; | ||
122 | irqtp->flags = 0; | ||
123 | call___do_IRQ(irq, regsParm, irqtp); | ||
124 | irqtp->task = NULL; | ||
125 | if (irqtp->flags) | ||
126 | set_bits(irqtp->flags, &curtp->flags); | ||
127 | } else | ||
128 | #endif | ||
129 | __do_IRQ(irq, regsParm); | ||
114 | HvCallPci_eoi(eventParm->eventData.slotInterrupt.busNumber, | 130 | HvCallPci_eoi(eventParm->eventData.slotInterrupt.busNumber, |
115 | eventParm->eventData.slotInterrupt.subBusNumber, | 131 | eventParm->eventData.slotInterrupt.subBusNumber, |
116 | eventParm->eventData.slotInterrupt.deviceId); | 132 | eventParm->eventData.slotInterrupt.deviceId); |
@@ -310,10 +326,8 @@ static void iSeries_disable_IRQ(unsigned int irq) | |||
310 | } | 326 | } |
311 | 327 | ||
312 | /* | 328 | /* |
313 | * Need to define this so ppc_irq_dispatch_handler will NOT call | 329 | * This does nothing because there is not enough information |
314 | * enable_IRQ at the end of interrupt handling. However, this does | 330 | * provided to do the EOI HvCall. This is done by XmPciLpEvent.c |
315 | * nothing because there is not enough information provided to do | ||
316 | * the EOI HvCall. This is done by XmPciLpEvent.c | ||
317 | */ | 331 | */ |
318 | static void iSeries_end_IRQ(unsigned int irq) | 332 | static void iSeries_end_IRQ(unsigned int irq) |
319 | { | 333 | { |
diff --git a/arch/powerpc/platforms/iseries/misc.S b/arch/powerpc/platforms/iseries/misc.S index 09f14522e176..dfe7aa1ba098 100644 --- a/arch/powerpc/platforms/iseries/misc.S +++ b/arch/powerpc/platforms/iseries/misc.S | |||
@@ -15,6 +15,7 @@ | |||
15 | 15 | ||
16 | #include <asm/processor.h> | 16 | #include <asm/processor.h> |
17 | #include <asm/asm-offsets.h> | 17 | #include <asm/asm-offsets.h> |
18 | #include <asm/ppc_asm.h> | ||
18 | 19 | ||
19 | .text | 20 | .text |
20 | 21 | ||
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index 7f8f0cda6a74..6a29f301436b 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c | |||
@@ -39,7 +39,8 @@ | |||
39 | #include <asm/sections.h> | 39 | #include <asm/sections.h> |
40 | #include <asm/iommu.h> | 40 | #include <asm/iommu.h> |
41 | #include <asm/firmware.h> | 41 | #include <asm/firmware.h> |
42 | 42 | #include <asm/systemcfg.h> | |
43 | #include <asm/system.h> | ||
43 | #include <asm/time.h> | 44 | #include <asm/time.h> |
44 | #include <asm/paca.h> | 45 | #include <asm/paca.h> |
45 | #include <asm/cache.h> | 46 | #include <asm/cache.h> |
@@ -71,7 +72,7 @@ extern void hvlog(char *fmt, ...); | |||
71 | #endif | 72 | #endif |
72 | 73 | ||
73 | /* Function Prototypes */ | 74 | /* Function Prototypes */ |
74 | static void build_iSeries_Memory_Map(void); | 75 | static unsigned long build_iSeries_Memory_Map(void); |
75 | static void iseries_shared_idle(void); | 76 | static void iseries_shared_idle(void); |
76 | static void iseries_dedicated_idle(void); | 77 | static void iseries_dedicated_idle(void); |
77 | #ifdef CONFIG_PCI | 78 | #ifdef CONFIG_PCI |
@@ -84,7 +85,6 @@ static void iSeries_pci_final_fixup(void) { } | |||
84 | int piranha_simulator; | 85 | int piranha_simulator; |
85 | 86 | ||
86 | extern int rd_size; /* Defined in drivers/block/rd.c */ | 87 | extern int rd_size; /* Defined in drivers/block/rd.c */ |
87 | extern unsigned long klimit; | ||
88 | extern unsigned long embedded_sysmap_start; | 88 | extern unsigned long embedded_sysmap_start; |
89 | extern unsigned long embedded_sysmap_end; | 89 | extern unsigned long embedded_sysmap_end; |
90 | 90 | ||
@@ -403,9 +403,11 @@ void mschunks_alloc(unsigned long num_chunks) | |||
403 | * a table used to translate Linux's physical addresses to these | 403 | * a table used to translate Linux's physical addresses to these |
404 | * absolute addresses. Absolute addresses are needed when | 404 | * absolute addresses. Absolute addresses are needed when |
405 | * communicating with the hypervisor (e.g. to build HPT entries) | 405 | * communicating with the hypervisor (e.g. to build HPT entries) |
406 | * | ||
407 | * Returns the physical memory size | ||
406 | */ | 408 | */ |
407 | 409 | ||
408 | static void __init build_iSeries_Memory_Map(void) | 410 | static unsigned long __init build_iSeries_Memory_Map(void) |
409 | { | 411 | { |
410 | u32 loadAreaFirstChunk, loadAreaLastChunk, loadAreaSize; | 412 | u32 loadAreaFirstChunk, loadAreaLastChunk, loadAreaSize; |
411 | u32 nextPhysChunk; | 413 | u32 nextPhysChunk; |
@@ -538,7 +540,7 @@ static void __init build_iSeries_Memory_Map(void) | |||
538 | * which should be equal to | 540 | * which should be equal to |
539 | * nextPhysChunk | 541 | * nextPhysChunk |
540 | */ | 542 | */ |
541 | systemcfg->physicalMemorySize = chunk_to_addr(nextPhysChunk); | 543 | return chunk_to_addr(nextPhysChunk); |
542 | } | 544 | } |
543 | 545 | ||
544 | /* | 546 | /* |
@@ -564,8 +566,8 @@ static void __init iSeries_setup_arch(void) | |||
564 | printk("Max physical processors = %d\n", | 566 | printk("Max physical processors = %d\n", |
565 | itVpdAreas.xSlicMaxPhysicalProcs); | 567 | itVpdAreas.xSlicMaxPhysicalProcs); |
566 | 568 | ||
567 | systemcfg->processor = xIoHriProcessorVpd[procIx].xPVR; | 569 | _systemcfg->processor = xIoHriProcessorVpd[procIx].xPVR; |
568 | printk("Processor version = %x\n", systemcfg->processor); | 570 | printk("Processor version = %x\n", _systemcfg->processor); |
569 | } | 571 | } |
570 | 572 | ||
571 | static void iSeries_show_cpuinfo(struct seq_file *m) | 573 | static void iSeries_show_cpuinfo(struct seq_file *m) |
@@ -702,7 +704,6 @@ static void iseries_shared_idle(void) | |||
702 | 704 | ||
703 | static void iseries_dedicated_idle(void) | 705 | static void iseries_dedicated_idle(void) |
704 | { | 706 | { |
705 | long oldval; | ||
706 | set_thread_flag(TIF_POLLING_NRFLAG); | 707 | set_thread_flag(TIF_POLLING_NRFLAG); |
707 | 708 | ||
708 | while (1) { | 709 | while (1) { |
@@ -929,7 +930,7 @@ void dt_cpus(struct iseries_flat_dt *dt) | |||
929 | dt_end_node(dt); | 930 | dt_end_node(dt); |
930 | } | 931 | } |
931 | 932 | ||
932 | void build_flat_dt(struct iseries_flat_dt *dt) | 933 | void build_flat_dt(struct iseries_flat_dt *dt, unsigned long phys_mem_size) |
933 | { | 934 | { |
934 | u64 tmp[2]; | 935 | u64 tmp[2]; |
935 | 936 | ||
@@ -945,7 +946,7 @@ void build_flat_dt(struct iseries_flat_dt *dt) | |||
945 | dt_prop_str(dt, "name", "memory"); | 946 | dt_prop_str(dt, "name", "memory"); |
946 | dt_prop_str(dt, "device_type", "memory"); | 947 | dt_prop_str(dt, "device_type", "memory"); |
947 | tmp[0] = 0; | 948 | tmp[0] = 0; |
948 | tmp[1] = systemcfg->physicalMemorySize; | 949 | tmp[1] = phys_mem_size; |
949 | dt_prop_u64_list(dt, "reg", tmp, 2); | 950 | dt_prop_u64_list(dt, "reg", tmp, 2); |
950 | dt_end_node(dt); | 951 | dt_end_node(dt); |
951 | 952 | ||
@@ -965,13 +966,15 @@ void build_flat_dt(struct iseries_flat_dt *dt) | |||
965 | 966 | ||
966 | void * __init iSeries_early_setup(void) | 967 | void * __init iSeries_early_setup(void) |
967 | { | 968 | { |
969 | unsigned long phys_mem_size; | ||
970 | |||
968 | iSeries_fixup_klimit(); | 971 | iSeries_fixup_klimit(); |
969 | 972 | ||
970 | /* | 973 | /* |
971 | * Initialize the table which translate Linux physical addresses to | 974 | * Initialize the table which translate Linux physical addresses to |
972 | * AS/400 absolute addresses | 975 | * AS/400 absolute addresses |
973 | */ | 976 | */ |
974 | build_iSeries_Memory_Map(); | 977 | phys_mem_size = build_iSeries_Memory_Map(); |
975 | 978 | ||
976 | iSeries_get_cmdline(); | 979 | iSeries_get_cmdline(); |
977 | 980 | ||
@@ -981,7 +984,7 @@ void * __init iSeries_early_setup(void) | |||
981 | /* Parse early parameters, in particular mem=x */ | 984 | /* Parse early parameters, in particular mem=x */ |
982 | parse_early_param(); | 985 | parse_early_param(); |
983 | 986 | ||
984 | build_flat_dt(&iseries_dt); | 987 | build_flat_dt(&iseries_dt, phys_mem_size); |
985 | 988 | ||
986 | return (void *) __pa(&iseries_dt); | 989 | return (void *) __pa(&iseries_dt); |
987 | } | 990 | } |
diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c index 340c21caeae2..895aeb3f75d0 100644 --- a/arch/powerpc/platforms/maple/pci.c +++ b/arch/powerpc/platforms/maple/pci.c | |||
@@ -380,9 +380,6 @@ void __init maple_pcibios_fixup(void) | |||
380 | for_each_pci_dev(dev) | 380 | for_each_pci_dev(dev) |
381 | pci_read_irq_line(dev); | 381 | pci_read_irq_line(dev); |
382 | 382 | ||
383 | /* Do the mapping of the IO space */ | ||
384 | phbs_remap_io(); | ||
385 | |||
386 | DBG(" <- maple_pcibios_fixup\n"); | 383 | DBG(" <- maple_pcibios_fixup\n"); |
387 | } | 384 | } |
388 | 385 | ||
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index 8f818d092e2b..dfd41b9781a9 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c | |||
@@ -918,9 +918,6 @@ void __init pmac_pci_init(void) | |||
918 | PCI_DN(np)->busno = 0xf0; | 918 | PCI_DN(np)->busno = 0xf0; |
919 | } | 919 | } |
920 | 920 | ||
921 | /* map in PCI I/O space */ | ||
922 | phbs_remap_io(); | ||
923 | |||
924 | /* pmac_check_ht_link(); */ | 921 | /* pmac_check_ht_link(); */ |
925 | 922 | ||
926 | /* Tell pci.c to not use the common resource allocation mechanism */ | 923 | /* Tell pci.c to not use the common resource allocation mechanism */ |
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 83a49e80ac29..90040c49494d 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c | |||
@@ -74,6 +74,9 @@ static DEFINE_SPINLOCK(pmac_pic_lock); | |||
74 | #define GATWICK_IRQ_POOL_SIZE 10 | 74 | #define GATWICK_IRQ_POOL_SIZE 10 |
75 | static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE]; | 75 | static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE]; |
76 | 76 | ||
77 | #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) | ||
78 | static unsigned long ppc_lost_interrupts[NR_MASK_WORDS]; | ||
79 | |||
77 | /* | 80 | /* |
78 | * Mark an irq as "lost". This is only used on the pmac | 81 | * Mark an irq as "lost". This is only used on the pmac |
79 | * since it can lose interrupts (see pmac_set_irq_mask). | 82 | * since it can lose interrupts (see pmac_set_irq_mask). |
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index e1f9443cc872..957b09103422 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c | |||
@@ -305,9 +305,19 @@ static int __init smp_psurge_probe(void) | |||
305 | psurge_start = ioremap(PSURGE_START, 4); | 305 | psurge_start = ioremap(PSURGE_START, 4); |
306 | psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4); | 306 | psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4); |
307 | 307 | ||
308 | /* this is not actually strictly necessary -- paulus. */ | 308 | /* |
309 | for (i = 1; i < ncpus; ++i) | 309 | * This is necessary because OF doesn't know about the |
310 | smp_hw_index[i] = i; | 310 | * secondary cpu(s), and thus there aren't nodes in the |
311 | * device tree for them, and smp_setup_cpu_maps hasn't | ||
312 | * set their bits in cpu_possible_map and cpu_present_map. | ||
313 | */ | ||
314 | if (ncpus > NR_CPUS) | ||
315 | ncpus = NR_CPUS; | ||
316 | for (i = 1; i < ncpus ; ++i) { | ||
317 | cpu_set(i, cpu_present_map); | ||
318 | cpu_set(i, cpu_possible_map); | ||
319 | set_hard_smp_processor_id(i, i); | ||
320 | } | ||
311 | 321 | ||
312 | if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352); | 322 | if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352); |
313 | 323 | ||
@@ -348,6 +358,7 @@ static void __init psurge_dual_sync_tb(int cpu_nr) | |||
348 | int t; | 358 | int t; |
349 | 359 | ||
350 | set_dec(tb_ticks_per_jiffy); | 360 | set_dec(tb_ticks_per_jiffy); |
361 | /* XXX fixme */ | ||
351 | set_tb(0, 0); | 362 | set_tb(0, 0); |
352 | last_jiffy_stamp(cpu_nr) = 0; | 363 | last_jiffy_stamp(cpu_nr) = 0; |
353 | 364 | ||
@@ -363,8 +374,6 @@ static void __init psurge_dual_sync_tb(int cpu_nr) | |||
363 | 374 | ||
364 | /* now interrupt the secondary, starting both TBs */ | 375 | /* now interrupt the secondary, starting both TBs */ |
365 | psurge_set_ipi(1); | 376 | psurge_set_ipi(1); |
366 | |||
367 | smp_tb_synchronized = 1; | ||
368 | } | 377 | } |
369 | 378 | ||
370 | static struct irqaction psurge_irqaction = { | 379 | static struct irqaction psurge_irqaction = { |
@@ -625,9 +634,8 @@ void smp_core99_give_timebase(void) | |||
625 | for (t = 100000; t > 0 && sec_tb_reset; --t) | 634 | for (t = 100000; t > 0 && sec_tb_reset; --t) |
626 | udelay(10); | 635 | udelay(10); |
627 | if (sec_tb_reset) | 636 | if (sec_tb_reset) |
637 | /* XXX BUG_ON here? */ | ||
628 | printk(KERN_WARNING "Timeout waiting sync(2) on second CPU\n"); | 638 | printk(KERN_WARNING "Timeout waiting sync(2) on second CPU\n"); |
629 | else | ||
630 | smp_tb_synchronized = 1; | ||
631 | 639 | ||
632 | /* Now, restart the timebase by leaving the GPIO to an open collector */ | 640 | /* Now, restart the timebase by leaving the GPIO to an open collector */ |
633 | pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0); | 641 | pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0); |
@@ -810,19 +818,9 @@ static void __devinit smp_core99_setup_cpu(int cpu_nr) | |||
810 | } | 818 | } |
811 | 819 | ||
812 | 820 | ||
813 | /* Core99 Macs (dual G4s and G5s) */ | ||
814 | struct smp_ops_t core99_smp_ops = { | ||
815 | .message_pass = smp_mpic_message_pass, | ||
816 | .probe = smp_core99_probe, | ||
817 | .kick_cpu = smp_core99_kick_cpu, | ||
818 | .setup_cpu = smp_core99_setup_cpu, | ||
819 | .give_timebase = smp_core99_give_timebase, | ||
820 | .take_timebase = smp_core99_take_timebase, | ||
821 | }; | ||
822 | |||
823 | #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC32) | 821 | #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC32) |
824 | 822 | ||
825 | int __cpu_disable(void) | 823 | int smp_core99_cpu_disable(void) |
826 | { | 824 | { |
827 | cpu_clear(smp_processor_id(), cpu_online_map); | 825 | cpu_clear(smp_processor_id(), cpu_online_map); |
828 | 826 | ||
@@ -846,7 +844,7 @@ void cpu_die(void) | |||
846 | low_cpu_die(); | 844 | low_cpu_die(); |
847 | } | 845 | } |
848 | 846 | ||
849 | void __cpu_die(unsigned int cpu) | 847 | void smp_core99_cpu_die(unsigned int cpu) |
850 | { | 848 | { |
851 | int timeout; | 849 | int timeout; |
852 | 850 | ||
@@ -858,8 +856,21 @@ void __cpu_die(unsigned int cpu) | |||
858 | } | 856 | } |
859 | msleep(1); | 857 | msleep(1); |
860 | } | 858 | } |
861 | cpu_callin_map[cpu] = 0; | ||
862 | cpu_dead[cpu] = 0; | 859 | cpu_dead[cpu] = 0; |
863 | } | 860 | } |
864 | 861 | ||
865 | #endif | 862 | #endif |
863 | |||
864 | /* Core99 Macs (dual G4s and G5s) */ | ||
865 | struct smp_ops_t core99_smp_ops = { | ||
866 | .message_pass = smp_mpic_message_pass, | ||
867 | .probe = smp_core99_probe, | ||
868 | .kick_cpu = smp_core99_kick_cpu, | ||
869 | .setup_cpu = smp_core99_setup_cpu, | ||
870 | .give_timebase = smp_core99_give_timebase, | ||
871 | .take_timebase = smp_core99_take_timebase, | ||
872 | #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC32) | ||
873 | .cpu_disable = smp_core99_cpu_disable, | ||
874 | .cpu_die = smp_core99_cpu_die, | ||
875 | #endif | ||
876 | }; | ||
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index b9938fece781..e7ca5b1f591e 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile | |||
@@ -3,3 +3,5 @@ obj-y := pci.o lpar.o hvCall.o nvram.o reconfig.o \ | |||
3 | obj-$(CONFIG_SMP) += smp.o | 3 | obj-$(CONFIG_SMP) += smp.o |
4 | obj-$(CONFIG_IBMVIO) += vio.o | 4 | obj-$(CONFIG_IBMVIO) += vio.o |
5 | obj-$(CONFIG_XICS) += xics.o | 5 | obj-$(CONFIG_XICS) += xics.o |
6 | obj-$(CONFIG_SCANLOG) += scanlog.o | ||
7 | obj-$(CONFIG_EEH) += eeh.o eeh_event.o | ||
diff --git a/arch/ppc64/kernel/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 035d1b14a207..79de2310e70b 100644 --- a/arch/ppc64/kernel/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c | |||
@@ -1,39 +1,37 @@ | |||
1 | /* | 1 | /* |
2 | * eeh.c | 2 | * eeh.c |
3 | * Copyright (C) 2001 Dave Engebretsen & Todd Inglett IBM Corporation | 3 | * Copyright (C) 2001 Dave Engebretsen & Todd Inglett IBM Corporation |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
7 | * the Free Software Foundation; either version 2 of the License, or | 7 | * the Free Software Foundation; either version 2 of the License, or |
8 | * (at your option) any later version. | 8 | * (at your option) any later version. |
9 | * | 9 | * |
10 | * This program is distributed in the hope that it will be useful, | 10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU General Public License | 15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program; if not, write to the Free Software | 16 | * along with this program; if not, write to the Free Software |
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/bootmem.h> | 20 | #include <linux/delay.h> |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/list.h> | 22 | #include <linux/list.h> |
23 | #include <linux/mm.h> | ||
24 | #include <linux/notifier.h> | ||
25 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
26 | #include <linux/proc_fs.h> | 24 | #include <linux/proc_fs.h> |
27 | #include <linux/rbtree.h> | 25 | #include <linux/rbtree.h> |
28 | #include <linux/seq_file.h> | 26 | #include <linux/seq_file.h> |
29 | #include <linux/spinlock.h> | 27 | #include <linux/spinlock.h> |
28 | #include <asm/atomic.h> | ||
30 | #include <asm/eeh.h> | 29 | #include <asm/eeh.h> |
30 | #include <asm/eeh_event.h> | ||
31 | #include <asm/io.h> | 31 | #include <asm/io.h> |
32 | #include <asm/machdep.h> | 32 | #include <asm/machdep.h> |
33 | #include <asm/rtas.h> | ||
34 | #include <asm/atomic.h> | ||
35 | #include <asm/systemcfg.h> | ||
36 | #include <asm/ppc-pci.h> | 33 | #include <asm/ppc-pci.h> |
34 | #include <asm/rtas.h> | ||
37 | 35 | ||
38 | #undef DEBUG | 36 | #undef DEBUG |
39 | 37 | ||
@@ -49,8 +47,8 @@ | |||
49 | * were "empty": all reads return 0xff's and all writes are silently | 47 | * were "empty": all reads return 0xff's and all writes are silently |
50 | * ignored. EEH slot isolation events can be triggered by parity | 48 | * ignored. EEH slot isolation events can be triggered by parity |
51 | * errors on the address or data busses (e.g. during posted writes), | 49 | * errors on the address or data busses (e.g. during posted writes), |
52 | * which in turn might be caused by dust, vibration, humidity, | 50 | * which in turn might be caused by low voltage on the bus, dust, |
53 | * radioactivity or plain-old failed hardware. | 51 | * vibration, humidity, radioactivity or plain-old failed hardware. |
54 | * | 52 | * |
55 | * Note, however, that one of the leading causes of EEH slot | 53 | * Note, however, that one of the leading causes of EEH slot |
56 | * freeze events are buggy device drivers, buggy device microcode, | 54 | * freeze events are buggy device drivers, buggy device microcode, |
@@ -71,26 +69,15 @@ | |||
71 | * and sent out for processing. | 69 | * and sent out for processing. |
72 | */ | 70 | */ |
73 | 71 | ||
74 | /** Bus Unit ID macros; get low and hi 32-bits of the 64-bit BUID */ | 72 | /* If a device driver keeps reading an MMIO register in an interrupt |
75 | #define BUID_HI(buid) ((buid) >> 32) | ||
76 | #define BUID_LO(buid) ((buid) & 0xffffffff) | ||
77 | |||
78 | /* EEH event workqueue setup. */ | ||
79 | static DEFINE_SPINLOCK(eeh_eventlist_lock); | ||
80 | LIST_HEAD(eeh_eventlist); | ||
81 | static void eeh_event_handler(void *); | ||
82 | DECLARE_WORK(eeh_event_wq, eeh_event_handler, NULL); | ||
83 | |||
84 | static struct notifier_block *eeh_notifier_chain; | ||
85 | |||
86 | /* | ||
87 | * If a device driver keeps reading an MMIO register in an interrupt | ||
88 | * handler after a slot isolation event has occurred, we assume it | 73 | * handler after a slot isolation event has occurred, we assume it |
89 | * is broken and panic. This sets the threshold for how many read | 74 | * is broken and panic. This sets the threshold for how many read |
90 | * attempts we allow before panicking. | 75 | * attempts we allow before panicking. |
91 | */ | 76 | */ |
92 | #define EEH_MAX_FAILS 1000 | 77 | #define EEH_MAX_FAILS 100000 |
93 | static atomic_t eeh_fail_count; | 78 | |
79 | /* Misc forward declaraions */ | ||
80 | static void eeh_save_bars(struct pci_dev * pdev, struct pci_dn *pdn); | ||
94 | 81 | ||
95 | /* RTAS tokens */ | 82 | /* RTAS tokens */ |
96 | static int ibm_set_eeh_option; | 83 | static int ibm_set_eeh_option; |
@@ -101,12 +88,19 @@ static int ibm_slot_error_detail; | |||
101 | 88 | ||
102 | static int eeh_subsystem_enabled; | 89 | static int eeh_subsystem_enabled; |
103 | 90 | ||
91 | /* Lock to avoid races due to multiple reports of an error */ | ||
92 | static DEFINE_SPINLOCK(confirm_error_lock); | ||
93 | |||
104 | /* Buffer for reporting slot-error-detail rtas calls */ | 94 | /* Buffer for reporting slot-error-detail rtas calls */ |
105 | static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX]; | 95 | static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX]; |
106 | static DEFINE_SPINLOCK(slot_errbuf_lock); | 96 | static DEFINE_SPINLOCK(slot_errbuf_lock); |
107 | static int eeh_error_buf_size; | 97 | static int eeh_error_buf_size; |
108 | 98 | ||
109 | /* System monitoring statistics */ | 99 | /* System monitoring statistics */ |
100 | static DEFINE_PER_CPU(unsigned long, no_device); | ||
101 | static DEFINE_PER_CPU(unsigned long, no_dn); | ||
102 | static DEFINE_PER_CPU(unsigned long, no_cfg_addr); | ||
103 | static DEFINE_PER_CPU(unsigned long, ignored_check); | ||
110 | static DEFINE_PER_CPU(unsigned long, total_mmio_ffs); | 104 | static DEFINE_PER_CPU(unsigned long, total_mmio_ffs); |
111 | static DEFINE_PER_CPU(unsigned long, false_positives); | 105 | static DEFINE_PER_CPU(unsigned long, false_positives); |
112 | static DEFINE_PER_CPU(unsigned long, ignored_failures); | 106 | static DEFINE_PER_CPU(unsigned long, ignored_failures); |
@@ -224,9 +218,9 @@ pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo, | |||
224 | while (*p) { | 218 | while (*p) { |
225 | parent = *p; | 219 | parent = *p; |
226 | piar = rb_entry(parent, struct pci_io_addr_range, rb_node); | 220 | piar = rb_entry(parent, struct pci_io_addr_range, rb_node); |
227 | if (alo < piar->addr_lo) { | 221 | if (ahi < piar->addr_lo) { |
228 | p = &parent->rb_left; | 222 | p = &parent->rb_left; |
229 | } else if (ahi > piar->addr_hi) { | 223 | } else if (alo > piar->addr_hi) { |
230 | p = &parent->rb_right; | 224 | p = &parent->rb_right; |
231 | } else { | 225 | } else { |
232 | if (dev != piar->pcidev || | 226 | if (dev != piar->pcidev || |
@@ -245,6 +239,11 @@ pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo, | |||
245 | piar->pcidev = dev; | 239 | piar->pcidev = dev; |
246 | piar->flags = flags; | 240 | piar->flags = flags; |
247 | 241 | ||
242 | #ifdef DEBUG | ||
243 | printk(KERN_DEBUG "PIAR: insert range=[%lx:%lx] dev=%s\n", | ||
244 | alo, ahi, pci_name (dev)); | ||
245 | #endif | ||
246 | |||
248 | rb_link_node(&piar->rb_node, parent, p); | 247 | rb_link_node(&piar->rb_node, parent, p); |
249 | rb_insert_color(&piar->rb_node, &pci_io_addr_cache_root.rb_root); | 248 | rb_insert_color(&piar->rb_node, &pci_io_addr_cache_root.rb_root); |
250 | 249 | ||
@@ -260,18 +259,17 @@ static void __pci_addr_cache_insert_device(struct pci_dev *dev) | |||
260 | 259 | ||
261 | dn = pci_device_to_OF_node(dev); | 260 | dn = pci_device_to_OF_node(dev); |
262 | if (!dn) { | 261 | if (!dn) { |
263 | printk(KERN_WARNING "PCI: no pci dn found for dev=%s\n", | 262 | printk(KERN_WARNING "PCI: no pci dn found for dev=%s\n", pci_name(dev)); |
264 | pci_name(dev)); | ||
265 | return; | 263 | return; |
266 | } | 264 | } |
267 | 265 | ||
268 | /* Skip any devices for which EEH is not enabled. */ | 266 | /* Skip any devices for which EEH is not enabled. */ |
269 | pdn = dn->data; | 267 | pdn = PCI_DN(dn); |
270 | if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) || | 268 | if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) || |
271 | pdn->eeh_mode & EEH_MODE_NOCHECK) { | 269 | pdn->eeh_mode & EEH_MODE_NOCHECK) { |
272 | #ifdef DEBUG | 270 | #ifdef DEBUG |
273 | printk(KERN_INFO "PCI: skip building address cache for=%s\n", | 271 | printk(KERN_INFO "PCI: skip building address cache for=%s - %s\n", |
274 | pci_name(dev)); | 272 | pci_name(dev), pdn->node->full_name); |
275 | #endif | 273 | #endif |
276 | return; | 274 | return; |
277 | } | 275 | } |
@@ -307,7 +305,7 @@ static void __pci_addr_cache_insert_device(struct pci_dev *dev) | |||
307 | * we maintain a cache of devices that can be quickly searched. | 305 | * we maintain a cache of devices that can be quickly searched. |
308 | * This routine adds a device to that cache. | 306 | * This routine adds a device to that cache. |
309 | */ | 307 | */ |
310 | void pci_addr_cache_insert_device(struct pci_dev *dev) | 308 | static void pci_addr_cache_insert_device(struct pci_dev *dev) |
311 | { | 309 | { |
312 | unsigned long flags; | 310 | unsigned long flags; |
313 | 311 | ||
@@ -350,7 +348,7 @@ restart: | |||
350 | * the tree multiple times (once per resource). | 348 | * the tree multiple times (once per resource). |
351 | * But so what; device removal doesn't need to be that fast. | 349 | * But so what; device removal doesn't need to be that fast. |
352 | */ | 350 | */ |
353 | void pci_addr_cache_remove_device(struct pci_dev *dev) | 351 | static void pci_addr_cache_remove_device(struct pci_dev *dev) |
354 | { | 352 | { |
355 | unsigned long flags; | 353 | unsigned long flags; |
356 | 354 | ||
@@ -370,8 +368,12 @@ void pci_addr_cache_remove_device(struct pci_dev *dev) | |||
370 | */ | 368 | */ |
371 | void __init pci_addr_cache_build(void) | 369 | void __init pci_addr_cache_build(void) |
372 | { | 370 | { |
371 | struct device_node *dn; | ||
373 | struct pci_dev *dev = NULL; | 372 | struct pci_dev *dev = NULL; |
374 | 373 | ||
374 | if (!eeh_subsystem_enabled) | ||
375 | return; | ||
376 | |||
375 | spin_lock_init(&pci_io_addr_cache_root.piar_lock); | 377 | spin_lock_init(&pci_io_addr_cache_root.piar_lock); |
376 | 378 | ||
377 | while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { | 379 | while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { |
@@ -380,6 +382,10 @@ void __init pci_addr_cache_build(void) | |||
380 | continue; | 382 | continue; |
381 | } | 383 | } |
382 | pci_addr_cache_insert_device(dev); | 384 | pci_addr_cache_insert_device(dev); |
385 | |||
386 | /* Save the BAR's; firmware doesn't restore these after EEH reset */ | ||
387 | dn = pci_device_to_OF_node(dev); | ||
388 | eeh_save_bars(dev, PCI_DN(dn)); | ||
383 | } | 389 | } |
384 | 390 | ||
385 | #ifdef DEBUG | 391 | #ifdef DEBUG |
@@ -391,22 +397,26 @@ void __init pci_addr_cache_build(void) | |||
391 | /* --------------------------------------------------------------- */ | 397 | /* --------------------------------------------------------------- */ |
392 | /* Above lies the PCI Address Cache. Below lies the EEH event infrastructure */ | 398 | /* Above lies the PCI Address Cache. Below lies the EEH event infrastructure */ |
393 | 399 | ||
394 | /** | 400 | void eeh_slot_error_detail (struct pci_dn *pdn, int severity) |
395 | * eeh_register_notifier - Register to find out about EEH events. | ||
396 | * @nb: notifier block to callback on events | ||
397 | */ | ||
398 | int eeh_register_notifier(struct notifier_block *nb) | ||
399 | { | 401 | { |
400 | return notifier_chain_register(&eeh_notifier_chain, nb); | 402 | unsigned long flags; |
401 | } | 403 | int rc; |
402 | 404 | ||
403 | /** | 405 | /* Log the error with the rtas logger */ |
404 | * eeh_unregister_notifier - Unregister to an EEH event notifier. | 406 | spin_lock_irqsave(&slot_errbuf_lock, flags); |
405 | * @nb: notifier block to callback on events | 407 | memset(slot_errbuf, 0, eeh_error_buf_size); |
406 | */ | 408 | |
407 | int eeh_unregister_notifier(struct notifier_block *nb) | 409 | rc = rtas_call(ibm_slot_error_detail, |
408 | { | 410 | 8, 1, NULL, pdn->eeh_config_addr, |
409 | return notifier_chain_unregister(&eeh_notifier_chain, nb); | 411 | BUID_HI(pdn->phb->buid), |
412 | BUID_LO(pdn->phb->buid), NULL, 0, | ||
413 | virt_to_phys(slot_errbuf), | ||
414 | eeh_error_buf_size, | ||
415 | severity); | ||
416 | |||
417 | if (rc == 0) | ||
418 | log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0); | ||
419 | spin_unlock_irqrestore(&slot_errbuf_lock, flags); | ||
410 | } | 420 | } |
411 | 421 | ||
412 | /** | 422 | /** |
@@ -414,16 +424,16 @@ int eeh_unregister_notifier(struct notifier_block *nb) | |||
414 | * @dn: device node to read | 424 | * @dn: device node to read |
415 | * @rets: array to return results in | 425 | * @rets: array to return results in |
416 | */ | 426 | */ |
417 | static int read_slot_reset_state(struct device_node *dn, int rets[]) | 427 | static int read_slot_reset_state(struct pci_dn *pdn, int rets[]) |
418 | { | 428 | { |
419 | int token, outputs; | 429 | int token, outputs; |
420 | struct pci_dn *pdn = dn->data; | ||
421 | 430 | ||
422 | if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) { | 431 | if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) { |
423 | token = ibm_read_slot_reset_state2; | 432 | token = ibm_read_slot_reset_state2; |
424 | outputs = 4; | 433 | outputs = 4; |
425 | } else { | 434 | } else { |
426 | token = ibm_read_slot_reset_state; | 435 | token = ibm_read_slot_reset_state; |
436 | rets[2] = 0; /* fake PE Unavailable info */ | ||
427 | outputs = 3; | 437 | outputs = 3; |
428 | } | 438 | } |
429 | 439 | ||
@@ -432,87 +442,84 @@ static int read_slot_reset_state(struct device_node *dn, int rets[]) | |||
432 | } | 442 | } |
433 | 443 | ||
434 | /** | 444 | /** |
435 | * eeh_panic - call panic() for an eeh event that cannot be handled. | 445 | * eeh_token_to_phys - convert EEH address token to phys address |
436 | * The philosophy of this routine is that it is better to panic and | 446 | * @token i/o token, should be address in the form 0xA.... |
437 | * halt the OS than it is to risk possible data corruption by | ||
438 | * oblivious device drivers that don't know better. | ||
439 | * | ||
440 | * @dev pci device that had an eeh event | ||
441 | * @reset_state current reset state of the device slot | ||
442 | */ | 447 | */ |
443 | static void eeh_panic(struct pci_dev *dev, int reset_state) | 448 | static inline unsigned long eeh_token_to_phys(unsigned long token) |
444 | { | 449 | { |
445 | /* | 450 | pte_t *ptep; |
446 | * XXX We should create a separate sysctl for this. | 451 | unsigned long pa; |
447 | * | 452 | |
448 | * Since the panic_on_oops sysctl is used to halt the system | 453 | ptep = find_linux_pte(init_mm.pgd, token); |
449 | * in light of potential corruption, we can use it here. | 454 | if (!ptep) |
450 | */ | 455 | return token; |
451 | if (panic_on_oops) | 456 | pa = pte_pfn(*ptep) << PAGE_SHIFT; |
452 | panic("EEH: MMIO failure (%d) on device:%s\n", reset_state, | 457 | |
453 | pci_name(dev)); | 458 | return pa | (token & (PAGE_SIZE-1)); |
454 | else { | ||
455 | __get_cpu_var(ignored_failures)++; | ||
456 | printk(KERN_INFO "EEH: Ignored MMIO failure (%d) on device:%s\n", | ||
457 | reset_state, pci_name(dev)); | ||
458 | } | ||
459 | } | 459 | } |
460 | 460 | ||
461 | /** | 461 | /** |
462 | * eeh_event_handler - dispatch EEH events. The detection of a frozen | 462 | * Return the "partitionable endpoint" (pe) under which this device lies |
463 | * slot can occur inside an interrupt, where it can be hard to do | ||
464 | * anything about it. The goal of this routine is to pull these | ||
465 | * detection events out of the context of the interrupt handler, and | ||
466 | * re-dispatch them for processing at a later time in a normal context. | ||
467 | * | ||
468 | * @dummy - unused | ||
469 | */ | 463 | */ |
470 | static void eeh_event_handler(void *dummy) | 464 | static struct device_node * find_device_pe(struct device_node *dn) |
471 | { | 465 | { |
472 | unsigned long flags; | 466 | while ((dn->parent) && PCI_DN(dn->parent) && |
473 | struct eeh_event *event; | 467 | (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) { |
474 | 468 | dn = dn->parent; | |
475 | while (1) { | 469 | } |
476 | spin_lock_irqsave(&eeh_eventlist_lock, flags); | 470 | return dn; |
477 | event = NULL; | 471 | } |
478 | if (!list_empty(&eeh_eventlist)) { | ||
479 | event = list_entry(eeh_eventlist.next, struct eeh_event, list); | ||
480 | list_del(&event->list); | ||
481 | } | ||
482 | spin_unlock_irqrestore(&eeh_eventlist_lock, flags); | ||
483 | if (event == NULL) | ||
484 | break; | ||
485 | |||
486 | printk(KERN_INFO "EEH: MMIO failure (%d), notifiying device " | ||
487 | "%s\n", event->reset_state, | ||
488 | pci_name(event->dev)); | ||
489 | 472 | ||
490 | atomic_set(&eeh_fail_count, 0); | 473 | /** Mark all devices that are peers of this device as failed. |
491 | notifier_call_chain (&eeh_notifier_chain, | 474 | * Mark the device driver too, so that it can see the failure |
492 | EEH_NOTIFY_FREEZE, event); | 475 | * immediately; this is critical, since some drivers poll |
476 | * status registers in interrupts ... If a driver is polling, | ||
477 | * and the slot is frozen, then the driver can deadlock in | ||
478 | * an interrupt context, which is bad. | ||
479 | */ | ||
493 | 480 | ||
494 | __get_cpu_var(slot_resets)++; | 481 | static void __eeh_mark_slot (struct device_node *dn, int mode_flag) |
482 | { | ||
483 | while (dn) { | ||
484 | if (PCI_DN(dn)) { | ||
485 | PCI_DN(dn)->eeh_mode |= mode_flag; | ||
495 | 486 | ||
496 | pci_dev_put(event->dev); | 487 | if (dn->child) |
497 | kfree(event); | 488 | __eeh_mark_slot (dn->child, mode_flag); |
489 | } | ||
490 | dn = dn->sibling; | ||
498 | } | 491 | } |
499 | } | 492 | } |
500 | 493 | ||
501 | /** | 494 | void eeh_mark_slot (struct device_node *dn, int mode_flag) |
502 | * eeh_token_to_phys - convert EEH address token to phys address | ||
503 | * @token i/o token, should be address in the form 0xE.... | ||
504 | */ | ||
505 | static inline unsigned long eeh_token_to_phys(unsigned long token) | ||
506 | { | 495 | { |
507 | pte_t *ptep; | 496 | dn = find_device_pe (dn); |
508 | unsigned long pa; | 497 | PCI_DN(dn)->eeh_mode |= mode_flag; |
498 | __eeh_mark_slot (dn->child, mode_flag); | ||
499 | } | ||
509 | 500 | ||
510 | ptep = find_linux_pte(init_mm.pgd, token); | 501 | static void __eeh_clear_slot (struct device_node *dn, int mode_flag) |
511 | if (!ptep) | 502 | { |
512 | return token; | 503 | while (dn) { |
513 | pa = pte_pfn(*ptep) << PAGE_SHIFT; | 504 | if (PCI_DN(dn)) { |
505 | PCI_DN(dn)->eeh_mode &= ~mode_flag; | ||
506 | PCI_DN(dn)->eeh_check_count = 0; | ||
507 | if (dn->child) | ||
508 | __eeh_clear_slot (dn->child, mode_flag); | ||
509 | } | ||
510 | dn = dn->sibling; | ||
511 | } | ||
512 | } | ||
514 | 513 | ||
515 | return pa | (token & (PAGE_SIZE-1)); | 514 | void eeh_clear_slot (struct device_node *dn, int mode_flag) |
515 | { | ||
516 | unsigned long flags; | ||
517 | spin_lock_irqsave(&confirm_error_lock, flags); | ||
518 | dn = find_device_pe (dn); | ||
519 | PCI_DN(dn)->eeh_mode &= ~mode_flag; | ||
520 | PCI_DN(dn)->eeh_check_count = 0; | ||
521 | __eeh_clear_slot (dn->child, mode_flag); | ||
522 | spin_unlock_irqrestore(&confirm_error_lock, flags); | ||
516 | } | 523 | } |
517 | 524 | ||
518 | /** | 525 | /** |
@@ -526,7 +533,7 @@ static inline unsigned long eeh_token_to_phys(unsigned long token) | |||
526 | * will query firmware for the EEH status. | 533 | * will query firmware for the EEH status. |
527 | * | 534 | * |
528 | * Returns 0 if there has not been an EEH error; otherwise returns | 535 | * Returns 0 if there has not been an EEH error; otherwise returns |
529 | * a non-zero value and queues up a solt isolation event notification. | 536 | * a non-zero value and queues up a slot isolation event notification. |
530 | * | 537 | * |
531 | * It is safe to call this routine in an interrupt context. | 538 | * It is safe to call this routine in an interrupt context. |
532 | */ | 539 | */ |
@@ -535,42 +542,59 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) | |||
535 | int ret; | 542 | int ret; |
536 | int rets[3]; | 543 | int rets[3]; |
537 | unsigned long flags; | 544 | unsigned long flags; |
538 | int rc, reset_state; | ||
539 | struct eeh_event *event; | ||
540 | struct pci_dn *pdn; | 545 | struct pci_dn *pdn; |
546 | int rc = 0; | ||
541 | 547 | ||
542 | __get_cpu_var(total_mmio_ffs)++; | 548 | __get_cpu_var(total_mmio_ffs)++; |
543 | 549 | ||
544 | if (!eeh_subsystem_enabled) | 550 | if (!eeh_subsystem_enabled) |
545 | return 0; | 551 | return 0; |
546 | 552 | ||
547 | if (!dn) | 553 | if (!dn) { |
554 | __get_cpu_var(no_dn)++; | ||
548 | return 0; | 555 | return 0; |
549 | pdn = dn->data; | 556 | } |
557 | pdn = PCI_DN(dn); | ||
550 | 558 | ||
551 | /* Access to IO BARs might get this far and still not want checking. */ | 559 | /* Access to IO BARs might get this far and still not want checking. */ |
552 | if (!pdn->eeh_capable || !(pdn->eeh_mode & EEH_MODE_SUPPORTED) || | 560 | if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) || |
553 | pdn->eeh_mode & EEH_MODE_NOCHECK) { | 561 | pdn->eeh_mode & EEH_MODE_NOCHECK) { |
562 | __get_cpu_var(ignored_check)++; | ||
563 | #ifdef DEBUG | ||
564 | printk ("EEH:ignored check (%x) for %s %s\n", | ||
565 | pdn->eeh_mode, pci_name (dev), dn->full_name); | ||
566 | #endif | ||
554 | return 0; | 567 | return 0; |
555 | } | 568 | } |
556 | 569 | ||
557 | if (!pdn->eeh_config_addr) { | 570 | if (!pdn->eeh_config_addr) { |
571 | __get_cpu_var(no_cfg_addr)++; | ||
558 | return 0; | 572 | return 0; |
559 | } | 573 | } |
560 | 574 | ||
561 | /* | 575 | /* If we already have a pending isolation event for this |
562 | * If we already have a pending isolation event for this | 576 | * slot, we know it's bad already, we don't need to check. |
563 | * slot, we know it's bad already, we don't need to check... | 577 | * Do this checking under a lock; as multiple PCI devices |
578 | * in one slot might report errors simultaneously, and we | ||
579 | * only want one error recovery routine running. | ||
564 | */ | 580 | */ |
581 | spin_lock_irqsave(&confirm_error_lock, flags); | ||
582 | rc = 1; | ||
565 | if (pdn->eeh_mode & EEH_MODE_ISOLATED) { | 583 | if (pdn->eeh_mode & EEH_MODE_ISOLATED) { |
566 | atomic_inc(&eeh_fail_count); | 584 | pdn->eeh_check_count ++; |
567 | if (atomic_read(&eeh_fail_count) >= EEH_MAX_FAILS) { | 585 | if (pdn->eeh_check_count >= EEH_MAX_FAILS) { |
586 | printk (KERN_ERR "EEH: Device driver ignored %d bad reads, panicing\n", | ||
587 | pdn->eeh_check_count); | ||
588 | dump_stack(); | ||
589 | |||
568 | /* re-read the slot reset state */ | 590 | /* re-read the slot reset state */ |
569 | if (read_slot_reset_state(dn, rets) != 0) | 591 | if (read_slot_reset_state(pdn, rets) != 0) |
570 | rets[0] = -1; /* reset state unknown */ | 592 | rets[0] = -1; /* reset state unknown */ |
571 | eeh_panic(dev, rets[0]); | 593 | |
594 | /* If we are here, then we hit an infinite loop. Stop. */ | ||
595 | panic("EEH: MMIO halt (%d) on device:%s\n", rets[0], pci_name(dev)); | ||
572 | } | 596 | } |
573 | return 0; | 597 | goto dn_unlock; |
574 | } | 598 | } |
575 | 599 | ||
576 | /* | 600 | /* |
@@ -580,66 +604,69 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) | |||
580 | * function zero of a multi-function device. | 604 | * function zero of a multi-function device. |
581 | * In any case they must share a common PHB. | 605 | * In any case they must share a common PHB. |
582 | */ | 606 | */ |
583 | ret = read_slot_reset_state(dn, rets); | 607 | ret = read_slot_reset_state(pdn, rets); |
584 | if (!(ret == 0 && rets[1] == 1 && (rets[0] == 2 || rets[0] == 4))) { | 608 | |
609 | /* If the call to firmware failed, punt */ | ||
610 | if (ret != 0) { | ||
611 | printk(KERN_WARNING "EEH: read_slot_reset_state() failed; rc=%d dn=%s\n", | ||
612 | ret, dn->full_name); | ||
585 | __get_cpu_var(false_positives)++; | 613 | __get_cpu_var(false_positives)++; |
586 | return 0; | 614 | rc = 0; |
615 | goto dn_unlock; | ||
587 | } | 616 | } |
588 | 617 | ||
589 | /* prevent repeated reports of this failure */ | 618 | /* If EEH is not supported on this device, punt. */ |
590 | pdn->eeh_mode |= EEH_MODE_ISOLATED; | 619 | if (rets[1] != 1) { |
591 | 620 | printk(KERN_WARNING "EEH: event on unsupported device, rc=%d dn=%s\n", | |
592 | reset_state = rets[0]; | 621 | ret, dn->full_name); |
593 | 622 | __get_cpu_var(false_positives)++; | |
594 | spin_lock_irqsave(&slot_errbuf_lock, flags); | 623 | rc = 0; |
595 | memset(slot_errbuf, 0, eeh_error_buf_size); | 624 | goto dn_unlock; |
596 | 625 | } | |
597 | rc = rtas_call(ibm_slot_error_detail, | ||
598 | 8, 1, NULL, pdn->eeh_config_addr, | ||
599 | BUID_HI(pdn->phb->buid), | ||
600 | BUID_LO(pdn->phb->buid), NULL, 0, | ||
601 | virt_to_phys(slot_errbuf), | ||
602 | eeh_error_buf_size, | ||
603 | 1 /* Temporary Error */); | ||
604 | |||
605 | if (rc == 0) | ||
606 | log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0); | ||
607 | spin_unlock_irqrestore(&slot_errbuf_lock, flags); | ||
608 | 626 | ||
609 | printk(KERN_INFO "EEH: MMIO failure (%d) on device: %s %s\n", | 627 | /* If not the kind of error we know about, punt. */ |
610 | rets[0], dn->name, dn->full_name); | 628 | if (rets[0] != 2 && rets[0] != 4 && rets[0] != 5) { |
611 | event = kmalloc(sizeof(*event), GFP_ATOMIC); | 629 | __get_cpu_var(false_positives)++; |
612 | if (event == NULL) { | 630 | rc = 0; |
613 | eeh_panic(dev, reset_state); | 631 | goto dn_unlock; |
614 | return 1; | 632 | } |
615 | } | ||
616 | 633 | ||
617 | event->dev = dev; | 634 | /* Note that config-io to empty slots may fail; |
618 | event->dn = dn; | 635 | * we recognize empty because they don't have children. */ |
619 | event->reset_state = reset_state; | 636 | if ((rets[0] == 5) && (dn->child == NULL)) { |
637 | __get_cpu_var(false_positives)++; | ||
638 | rc = 0; | ||
639 | goto dn_unlock; | ||
640 | } | ||
620 | 641 | ||
621 | /* We may or may not be called in an interrupt context */ | 642 | __get_cpu_var(slot_resets)++; |
622 | spin_lock_irqsave(&eeh_eventlist_lock, flags); | 643 | |
623 | list_add(&event->list, &eeh_eventlist); | 644 | /* Avoid repeated reports of this failure, including problems |
624 | spin_unlock_irqrestore(&eeh_eventlist_lock, flags); | 645 | * with other functions on this device, and functions under |
646 | * bridges. */ | ||
647 | eeh_mark_slot (dn, EEH_MODE_ISOLATED); | ||
648 | spin_unlock_irqrestore(&confirm_error_lock, flags); | ||
625 | 649 | ||
650 | eeh_send_failure_event (dn, dev, rets[0], rets[2]); | ||
651 | |||
626 | /* Most EEH events are due to device driver bugs. Having | 652 | /* Most EEH events are due to device driver bugs. Having |
627 | * a stack trace will help the device-driver authors figure | 653 | * a stack trace will help the device-driver authors figure |
628 | * out what happened. So print that out. */ | 654 | * out what happened. So print that out. */ |
629 | dump_stack(); | 655 | if (rets[0] != 5) dump_stack(); |
630 | schedule_work(&eeh_event_wq); | 656 | return 1; |
631 | 657 | ||
632 | return 0; | 658 | dn_unlock: |
659 | spin_unlock_irqrestore(&confirm_error_lock, flags); | ||
660 | return rc; | ||
633 | } | 661 | } |
634 | 662 | ||
635 | EXPORT_SYMBOL(eeh_dn_check_failure); | 663 | EXPORT_SYMBOL_GPL(eeh_dn_check_failure); |
636 | 664 | ||
637 | /** | 665 | /** |
638 | * eeh_check_failure - check if all 1's data is due to EEH slot freeze | 666 | * eeh_check_failure - check if all 1's data is due to EEH slot freeze |
639 | * @token i/o token, should be address in the form 0xA.... | 667 | * @token i/o token, should be address in the form 0xA.... |
640 | * @val value, should be all 1's (XXX why do we need this arg??) | 668 | * @val value, should be all 1's (XXX why do we need this arg??) |
641 | * | 669 | * |
642 | * Check for an eeh failure at the given token address. | ||
643 | * Check for an EEH failure at the given token address. Call this | 670 | * Check for an EEH failure at the given token address. Call this |
644 | * routine if the result of a read was all 0xff's and you want to | 671 | * routine if the result of a read was all 0xff's and you want to |
645 | * find out if this is due to an EEH slot freeze event. This routine | 672 | * find out if this is due to an EEH slot freeze event. This routine |
@@ -656,8 +683,10 @@ unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned lon | |||
656 | /* Finding the phys addr + pci device; this is pretty quick. */ | 683 | /* Finding the phys addr + pci device; this is pretty quick. */ |
657 | addr = eeh_token_to_phys((unsigned long __force) token); | 684 | addr = eeh_token_to_phys((unsigned long __force) token); |
658 | dev = pci_get_device_by_addr(addr); | 685 | dev = pci_get_device_by_addr(addr); |
659 | if (!dev) | 686 | if (!dev) { |
687 | __get_cpu_var(no_device)++; | ||
660 | return val; | 688 | return val; |
689 | } | ||
661 | 690 | ||
662 | dn = pci_device_to_OF_node(dev); | 691 | dn = pci_device_to_OF_node(dev); |
663 | eeh_dn_check_failure (dn, dev); | 692 | eeh_dn_check_failure (dn, dev); |
@@ -668,6 +697,217 @@ unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned lon | |||
668 | 697 | ||
669 | EXPORT_SYMBOL(eeh_check_failure); | 698 | EXPORT_SYMBOL(eeh_check_failure); |
670 | 699 | ||
700 | /* ------------------------------------------------------------- */ | ||
701 | /* The code below deals with error recovery */ | ||
702 | |||
703 | /** Return negative value if a permanent error, else return | ||
704 | * a number of milliseconds to wait until the PCI slot is | ||
705 | * ready to be used. | ||
706 | */ | ||
707 | static int | ||
708 | eeh_slot_availability(struct pci_dn *pdn) | ||
709 | { | ||
710 | int rc; | ||
711 | int rets[3]; | ||
712 | |||
713 | rc = read_slot_reset_state(pdn, rets); | ||
714 | |||
715 | if (rc) return rc; | ||
716 | |||
717 | if (rets[1] == 0) return -1; /* EEH is not supported */ | ||
718 | if (rets[0] == 0) return 0; /* Oll Korrect */ | ||
719 | if (rets[0] == 5) { | ||
720 | if (rets[2] == 0) return -1; /* permanently unavailable */ | ||
721 | return rets[2]; /* number of millisecs to wait */ | ||
722 | } | ||
723 | return -1; | ||
724 | } | ||
725 | |||
726 | /** rtas_pci_slot_reset raises/lowers the pci #RST line | ||
727 | * state: 1/0 to raise/lower the #RST | ||
728 | * | ||
729 | * Clear the EEH-frozen condition on a slot. This routine | ||
730 | * asserts the PCI #RST line if the 'state' argument is '1', | ||
731 | * and drops the #RST line if 'state is '0'. This routine is | ||
732 | * safe to call in an interrupt context. | ||
733 | * | ||
734 | */ | ||
735 | |||
736 | static void | ||
737 | rtas_pci_slot_reset(struct pci_dn *pdn, int state) | ||
738 | { | ||
739 | int rc; | ||
740 | |||
741 | BUG_ON (pdn==NULL); | ||
742 | |||
743 | if (!pdn->phb) { | ||
744 | printk (KERN_WARNING "EEH: in slot reset, device node %s has no phb\n", | ||
745 | pdn->node->full_name); | ||
746 | return; | ||
747 | } | ||
748 | |||
749 | rc = rtas_call(ibm_set_slot_reset,4,1, NULL, | ||
750 | pdn->eeh_config_addr, | ||
751 | BUID_HI(pdn->phb->buid), | ||
752 | BUID_LO(pdn->phb->buid), | ||
753 | state); | ||
754 | if (rc) { | ||
755 | printk (KERN_WARNING "EEH: Unable to reset the failed slot, (%d) #RST=%d dn=%s\n", | ||
756 | rc, state, pdn->node->full_name); | ||
757 | return; | ||
758 | } | ||
759 | } | ||
760 | |||
761 | /** rtas_set_slot_reset -- assert the pci #RST line for 1/4 second | ||
762 | * dn -- device node to be reset. | ||
763 | */ | ||
764 | |||
765 | void | ||
766 | rtas_set_slot_reset(struct pci_dn *pdn) | ||
767 | { | ||
768 | int i, rc; | ||
769 | |||
770 | rtas_pci_slot_reset (pdn, 1); | ||
771 | |||
772 | /* The PCI bus requires that the reset be held high for at least | ||
773 | * a 100 milliseconds. We wait a bit longer 'just in case'. */ | ||
774 | |||
775 | #define PCI_BUS_RST_HOLD_TIME_MSEC 250 | ||
776 | msleep (PCI_BUS_RST_HOLD_TIME_MSEC); | ||
777 | |||
778 | /* We might get hit with another EEH freeze as soon as the | ||
779 | * pci slot reset line is dropped. Make sure we don't miss | ||
780 | * these, and clear the flag now. */ | ||
781 | eeh_clear_slot (pdn->node, EEH_MODE_ISOLATED); | ||
782 | |||
783 | rtas_pci_slot_reset (pdn, 0); | ||
784 | |||
785 | /* After a PCI slot has been reset, the PCI Express spec requires | ||
786 | * a 1.5 second idle time for the bus to stabilize, before starting | ||
787 | * up traffic. */ | ||
788 | #define PCI_BUS_SETTLE_TIME_MSEC 1800 | ||
789 | msleep (PCI_BUS_SETTLE_TIME_MSEC); | ||
790 | |||
791 | /* Now double check with the firmware to make sure the device is | ||
792 | * ready to be used; if not, wait for recovery. */ | ||
793 | for (i=0; i<10; i++) { | ||
794 | rc = eeh_slot_availability (pdn); | ||
795 | if (rc <= 0) break; | ||
796 | |||
797 | msleep (rc+100); | ||
798 | } | ||
799 | } | ||
800 | |||
801 | /* ------------------------------------------------------- */ | ||
802 | /** Save and restore of PCI BARs | ||
803 | * | ||
804 | * Although firmware will set up BARs during boot, it doesn't | ||
805 | * set up device BAR's after a device reset, although it will, | ||
806 | * if requested, set up bridge configuration. Thus, we need to | ||
807 | * configure the PCI devices ourselves. | ||
808 | */ | ||
809 | |||
810 | /** | ||
811 | * __restore_bars - Restore the Base Address Registers | ||
812 | * Loads the PCI configuration space base address registers, | ||
813 | * the expansion ROM base address, the latency timer, and etc. | ||
814 | * from the saved values in the device node. | ||
815 | */ | ||
816 | static inline void __restore_bars (struct pci_dn *pdn) | ||
817 | { | ||
818 | int i; | ||
819 | |||
820 | if (NULL==pdn->phb) return; | ||
821 | for (i=4; i<10; i++) { | ||
822 | rtas_write_config(pdn, i*4, 4, pdn->config_space[i]); | ||
823 | } | ||
824 | |||
825 | /* 12 == Expansion ROM Address */ | ||
826 | rtas_write_config(pdn, 12*4, 4, pdn->config_space[12]); | ||
827 | |||
828 | #define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF)) | ||
829 | #define SAVED_BYTE(OFF) (((u8 *)(pdn->config_space))[BYTE_SWAP(OFF)]) | ||
830 | |||
831 | rtas_write_config (pdn, PCI_CACHE_LINE_SIZE, 1, | ||
832 | SAVED_BYTE(PCI_CACHE_LINE_SIZE)); | ||
833 | |||
834 | rtas_write_config (pdn, PCI_LATENCY_TIMER, 1, | ||
835 | SAVED_BYTE(PCI_LATENCY_TIMER)); | ||
836 | |||
837 | /* max latency, min grant, interrupt pin and line */ | ||
838 | rtas_write_config(pdn, 15*4, 4, pdn->config_space[15]); | ||
839 | } | ||
840 | |||
841 | /** | ||
842 | * eeh_restore_bars - restore the PCI config space info | ||
843 | * | ||
844 | * This routine performs a recursive walk to the children | ||
845 | * of this device as well. | ||
846 | */ | ||
847 | void eeh_restore_bars(struct pci_dn *pdn) | ||
848 | { | ||
849 | struct device_node *dn; | ||
850 | if (!pdn) | ||
851 | return; | ||
852 | |||
853 | if (! pdn->eeh_is_bridge) | ||
854 | __restore_bars (pdn); | ||
855 | |||
856 | dn = pdn->node->child; | ||
857 | while (dn) { | ||
858 | eeh_restore_bars (PCI_DN(dn)); | ||
859 | dn = dn->sibling; | ||
860 | } | ||
861 | } | ||
862 | |||
863 | /** | ||
864 | * eeh_save_bars - save device bars | ||
865 | * | ||
866 | * Save the values of the device bars. Unlike the restore | ||
867 | * routine, this routine is *not* recursive. This is because | ||
868 | * PCI devices are added individuallly; but, for the restore, | ||
869 | * an entire slot is reset at a time. | ||
870 | */ | ||
871 | static void eeh_save_bars(struct pci_dev * pdev, struct pci_dn *pdn) | ||
872 | { | ||
873 | int i; | ||
874 | |||
875 | if (!pdev || !pdn ) | ||
876 | return; | ||
877 | |||
878 | for (i = 0; i < 16; i++) | ||
879 | pci_read_config_dword(pdev, i * 4, &pdn->config_space[i]); | ||
880 | |||
881 | if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) | ||
882 | pdn->eeh_is_bridge = 1; | ||
883 | } | ||
884 | |||
885 | void | ||
886 | rtas_configure_bridge(struct pci_dn *pdn) | ||
887 | { | ||
888 | int token = rtas_token ("ibm,configure-bridge"); | ||
889 | int rc; | ||
890 | |||
891 | if (token == RTAS_UNKNOWN_SERVICE) | ||
892 | return; | ||
893 | rc = rtas_call(token,3,1, NULL, | ||
894 | pdn->eeh_config_addr, | ||
895 | BUID_HI(pdn->phb->buid), | ||
896 | BUID_LO(pdn->phb->buid)); | ||
897 | if (rc) { | ||
898 | printk (KERN_WARNING "EEH: Unable to configure device bridge (%d) for %s\n", | ||
899 | rc, pdn->node->full_name); | ||
900 | } | ||
901 | } | ||
902 | |||
903 | /* ------------------------------------------------------------- */ | ||
904 | /* The code below deals with enabling EEH for devices during the | ||
905 | * early boot sequence. EEH must be enabled before any PCI probing | ||
906 | * can be done. | ||
907 | */ | ||
908 | |||
909 | #define EEH_ENABLE 1 | ||
910 | |||
671 | struct eeh_early_enable_info { | 911 | struct eeh_early_enable_info { |
672 | unsigned int buid_hi; | 912 | unsigned int buid_hi; |
673 | unsigned int buid_lo; | 913 | unsigned int buid_lo; |
@@ -684,9 +924,11 @@ static void *early_enable_eeh(struct device_node *dn, void *data) | |||
684 | u32 *device_id = (u32 *)get_property(dn, "device-id", NULL); | 924 | u32 *device_id = (u32 *)get_property(dn, "device-id", NULL); |
685 | u32 *regs; | 925 | u32 *regs; |
686 | int enable; | 926 | int enable; |
687 | struct pci_dn *pdn = dn->data; | 927 | struct pci_dn *pdn = PCI_DN(dn); |
688 | 928 | ||
689 | pdn->eeh_mode = 0; | 929 | pdn->eeh_mode = 0; |
930 | pdn->eeh_check_count = 0; | ||
931 | pdn->eeh_freeze_count = 0; | ||
690 | 932 | ||
691 | if (status && strcmp(status, "ok") != 0) | 933 | if (status && strcmp(status, "ok") != 0) |
692 | return NULL; /* ignore devices with bad status */ | 934 | return NULL; /* ignore devices with bad status */ |
@@ -723,8 +965,9 @@ static void *early_enable_eeh(struct device_node *dn, void *data) | |||
723 | /* First register entry is addr (00BBSS00) */ | 965 | /* First register entry is addr (00BBSS00) */ |
724 | /* Try to enable eeh */ | 966 | /* Try to enable eeh */ |
725 | ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL, | 967 | ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL, |
726 | regs[0], info->buid_hi, info->buid_lo, | 968 | regs[0], info->buid_hi, info->buid_lo, |
727 | EEH_ENABLE); | 969 | EEH_ENABLE); |
970 | |||
728 | if (ret == 0) { | 971 | if (ret == 0) { |
729 | eeh_subsystem_enabled = 1; | 972 | eeh_subsystem_enabled = 1; |
730 | pdn->eeh_mode |= EEH_MODE_SUPPORTED; | 973 | pdn->eeh_mode |= EEH_MODE_SUPPORTED; |
@@ -736,7 +979,7 @@ static void *early_enable_eeh(struct device_node *dn, void *data) | |||
736 | 979 | ||
737 | /* This device doesn't support EEH, but it may have an | 980 | /* This device doesn't support EEH, but it may have an |
738 | * EEH parent, in which case we mark it as supported. */ | 981 | * EEH parent, in which case we mark it as supported. */ |
739 | if (dn->parent && dn->parent->data | 982 | if (dn->parent && PCI_DN(dn->parent) |
740 | && (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) { | 983 | && (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) { |
741 | /* Parent supports EEH. */ | 984 | /* Parent supports EEH. */ |
742 | pdn->eeh_mode |= EEH_MODE_SUPPORTED; | 985 | pdn->eeh_mode |= EEH_MODE_SUPPORTED; |
@@ -749,7 +992,7 @@ static void *early_enable_eeh(struct device_node *dn, void *data) | |||
749 | dn->full_name); | 992 | dn->full_name); |
750 | } | 993 | } |
751 | 994 | ||
752 | return NULL; | 995 | return NULL; |
753 | } | 996 | } |
754 | 997 | ||
755 | /* | 998 | /* |
@@ -770,6 +1013,9 @@ void __init eeh_init(void) | |||
770 | struct device_node *phb, *np; | 1013 | struct device_node *phb, *np; |
771 | struct eeh_early_enable_info info; | 1014 | struct eeh_early_enable_info info; |
772 | 1015 | ||
1016 | spin_lock_init(&confirm_error_lock); | ||
1017 | spin_lock_init(&slot_errbuf_lock); | ||
1018 | |||
773 | np = of_find_node_by_path("/rtas"); | 1019 | np = of_find_node_by_path("/rtas"); |
774 | if (np == NULL) | 1020 | if (np == NULL) |
775 | return; | 1021 | return; |
@@ -797,13 +1043,11 @@ void __init eeh_init(void) | |||
797 | for (phb = of_find_node_by_name(NULL, "pci"); phb; | 1043 | for (phb = of_find_node_by_name(NULL, "pci"); phb; |
798 | phb = of_find_node_by_name(phb, "pci")) { | 1044 | phb = of_find_node_by_name(phb, "pci")) { |
799 | unsigned long buid; | 1045 | unsigned long buid; |
800 | struct pci_dn *pci; | ||
801 | 1046 | ||
802 | buid = get_phb_buid(phb); | 1047 | buid = get_phb_buid(phb); |
803 | if (buid == 0 || phb->data == NULL) | 1048 | if (buid == 0 || PCI_DN(phb) == NULL) |
804 | continue; | 1049 | continue; |
805 | 1050 | ||
806 | pci = phb->data; | ||
807 | info.buid_lo = BUID_LO(buid); | 1051 | info.buid_lo = BUID_LO(buid); |
808 | info.buid_hi = BUID_HI(buid); | 1052 | info.buid_hi = BUID_HI(buid); |
809 | traverse_pci_devices(phb, early_enable_eeh, &info); | 1053 | traverse_pci_devices(phb, early_enable_eeh, &info); |
@@ -832,11 +1076,13 @@ void eeh_add_device_early(struct device_node *dn) | |||
832 | struct pci_controller *phb; | 1076 | struct pci_controller *phb; |
833 | struct eeh_early_enable_info info; | 1077 | struct eeh_early_enable_info info; |
834 | 1078 | ||
835 | if (!dn || !dn->data) | 1079 | if (!dn || !PCI_DN(dn)) |
836 | return; | 1080 | return; |
837 | phb = PCI_DN(dn)->phb; | 1081 | phb = PCI_DN(dn)->phb; |
838 | if (NULL == phb || 0 == phb->buid) { | 1082 | if (NULL == phb || 0 == phb->buid) { |
839 | printk(KERN_WARNING "EEH: Expected buid but found none\n"); | 1083 | printk(KERN_WARNING "EEH: Expected buid but found none for %s\n", |
1084 | dn->full_name); | ||
1085 | dump_stack(); | ||
840 | return; | 1086 | return; |
841 | } | 1087 | } |
842 | 1088 | ||
@@ -844,7 +1090,7 @@ void eeh_add_device_early(struct device_node *dn) | |||
844 | info.buid_lo = BUID_LO(phb->buid); | 1090 | info.buid_lo = BUID_LO(phb->buid); |
845 | early_enable_eeh(dn, &info); | 1091 | early_enable_eeh(dn, &info); |
846 | } | 1092 | } |
847 | EXPORT_SYMBOL(eeh_add_device_early); | 1093 | EXPORT_SYMBOL_GPL(eeh_add_device_early); |
848 | 1094 | ||
849 | /** | 1095 | /** |
850 | * eeh_add_device_late - perform EEH initialization for the indicated pci device | 1096 | * eeh_add_device_late - perform EEH initialization for the indicated pci device |
@@ -855,6 +1101,9 @@ EXPORT_SYMBOL(eeh_add_device_early); | |||
855 | */ | 1101 | */ |
856 | void eeh_add_device_late(struct pci_dev *dev) | 1102 | void eeh_add_device_late(struct pci_dev *dev) |
857 | { | 1103 | { |
1104 | struct device_node *dn; | ||
1105 | struct pci_dn *pdn; | ||
1106 | |||
858 | if (!dev || !eeh_subsystem_enabled) | 1107 | if (!dev || !eeh_subsystem_enabled) |
859 | return; | 1108 | return; |
860 | 1109 | ||
@@ -862,9 +1111,15 @@ void eeh_add_device_late(struct pci_dev *dev) | |||
862 | printk(KERN_DEBUG "EEH: adding device %s\n", pci_name(dev)); | 1111 | printk(KERN_DEBUG "EEH: adding device %s\n", pci_name(dev)); |
863 | #endif | 1112 | #endif |
864 | 1113 | ||
1114 | pci_dev_get (dev); | ||
1115 | dn = pci_device_to_OF_node(dev); | ||
1116 | pdn = PCI_DN(dn); | ||
1117 | pdn->pcidev = dev; | ||
1118 | |||
865 | pci_addr_cache_insert_device (dev); | 1119 | pci_addr_cache_insert_device (dev); |
1120 | eeh_save_bars(dev, pdn); | ||
866 | } | 1121 | } |
867 | EXPORT_SYMBOL(eeh_add_device_late); | 1122 | EXPORT_SYMBOL_GPL(eeh_add_device_late); |
868 | 1123 | ||
869 | /** | 1124 | /** |
870 | * eeh_remove_device - undo EEH setup for the indicated pci device | 1125 | * eeh_remove_device - undo EEH setup for the indicated pci device |
@@ -875,6 +1130,7 @@ EXPORT_SYMBOL(eeh_add_device_late); | |||
875 | */ | 1130 | */ |
876 | void eeh_remove_device(struct pci_dev *dev) | 1131 | void eeh_remove_device(struct pci_dev *dev) |
877 | { | 1132 | { |
1133 | struct device_node *dn; | ||
878 | if (!dev || !eeh_subsystem_enabled) | 1134 | if (!dev || !eeh_subsystem_enabled) |
879 | return; | 1135 | return; |
880 | 1136 | ||
@@ -883,20 +1139,29 @@ void eeh_remove_device(struct pci_dev *dev) | |||
883 | printk(KERN_DEBUG "EEH: remove device %s\n", pci_name(dev)); | 1139 | printk(KERN_DEBUG "EEH: remove device %s\n", pci_name(dev)); |
884 | #endif | 1140 | #endif |
885 | pci_addr_cache_remove_device(dev); | 1141 | pci_addr_cache_remove_device(dev); |
1142 | |||
1143 | dn = pci_device_to_OF_node(dev); | ||
1144 | PCI_DN(dn)->pcidev = NULL; | ||
1145 | pci_dev_put (dev); | ||
886 | } | 1146 | } |
887 | EXPORT_SYMBOL(eeh_remove_device); | 1147 | EXPORT_SYMBOL_GPL(eeh_remove_device); |
888 | 1148 | ||
889 | static int proc_eeh_show(struct seq_file *m, void *v) | 1149 | static int proc_eeh_show(struct seq_file *m, void *v) |
890 | { | 1150 | { |
891 | unsigned int cpu; | 1151 | unsigned int cpu; |
892 | unsigned long ffs = 0, positives = 0, failures = 0; | 1152 | unsigned long ffs = 0, positives = 0, failures = 0; |
893 | unsigned long resets = 0; | 1153 | unsigned long resets = 0; |
1154 | unsigned long no_dev = 0, no_dn = 0, no_cfg = 0, no_check = 0; | ||
894 | 1155 | ||
895 | for_each_cpu(cpu) { | 1156 | for_each_cpu(cpu) { |
896 | ffs += per_cpu(total_mmio_ffs, cpu); | 1157 | ffs += per_cpu(total_mmio_ffs, cpu); |
897 | positives += per_cpu(false_positives, cpu); | 1158 | positives += per_cpu(false_positives, cpu); |
898 | failures += per_cpu(ignored_failures, cpu); | 1159 | failures += per_cpu(ignored_failures, cpu); |
899 | resets += per_cpu(slot_resets, cpu); | 1160 | resets += per_cpu(slot_resets, cpu); |
1161 | no_dev += per_cpu(no_device, cpu); | ||
1162 | no_dn += per_cpu(no_dn, cpu); | ||
1163 | no_cfg += per_cpu(no_cfg_addr, cpu); | ||
1164 | no_check += per_cpu(ignored_check, cpu); | ||
900 | } | 1165 | } |
901 | 1166 | ||
902 | if (0 == eeh_subsystem_enabled) { | 1167 | if (0 == eeh_subsystem_enabled) { |
@@ -904,13 +1169,17 @@ static int proc_eeh_show(struct seq_file *m, void *v) | |||
904 | seq_printf(m, "eeh_total_mmio_ffs=%ld\n", ffs); | 1169 | seq_printf(m, "eeh_total_mmio_ffs=%ld\n", ffs); |
905 | } else { | 1170 | } else { |
906 | seq_printf(m, "EEH Subsystem is enabled\n"); | 1171 | seq_printf(m, "EEH Subsystem is enabled\n"); |
907 | seq_printf(m, "eeh_total_mmio_ffs=%ld\n" | 1172 | seq_printf(m, |
908 | "eeh_false_positives=%ld\n" | 1173 | "no device=%ld\n" |
909 | "eeh_ignored_failures=%ld\n" | 1174 | "no device node=%ld\n" |
910 | "eeh_slot_resets=%ld\n" | 1175 | "no config address=%ld\n" |
911 | "eeh_fail_count=%d\n", | 1176 | "check not wanted=%ld\n" |
912 | ffs, positives, failures, resets, | 1177 | "eeh_total_mmio_ffs=%ld\n" |
913 | eeh_fail_count.counter); | 1178 | "eeh_false_positives=%ld\n" |
1179 | "eeh_ignored_failures=%ld\n" | ||
1180 | "eeh_slot_resets=%ld\n", | ||
1181 | no_dev, no_dn, no_cfg, no_check, | ||
1182 | ffs, positives, failures, resets); | ||
914 | } | 1183 | } |
915 | 1184 | ||
916 | return 0; | 1185 | return 0; |
@@ -932,7 +1201,7 @@ static int __init eeh_init_proc(void) | |||
932 | { | 1201 | { |
933 | struct proc_dir_entry *e; | 1202 | struct proc_dir_entry *e; |
934 | 1203 | ||
935 | if (systemcfg->platform & PLATFORM_PSERIES) { | 1204 | if (platform_is_pseries()) { |
936 | e = create_proc_entry("ppc64/eeh", 0, NULL); | 1205 | e = create_proc_entry("ppc64/eeh", 0, NULL); |
937 | if (e) | 1206 | if (e) |
938 | e->proc_fops = &proc_eeh_operations; | 1207 | e->proc_fops = &proc_eeh_operations; |
diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c new file mode 100644 index 000000000000..92497333c2b6 --- /dev/null +++ b/arch/powerpc/platforms/pseries/eeh_event.c | |||
@@ -0,0 +1,155 @@ | |||
1 | /* | ||
2 | * eeh_event.c | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | * | ||
18 | * Copyright (c) 2005 Linas Vepstas <linas@linas.org> | ||
19 | */ | ||
20 | |||
21 | #include <linux/list.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <asm/eeh_event.h> | ||
24 | |||
25 | /** Overview: | ||
26 | * EEH error states may be detected within exception handlers; | ||
27 | * however, the recovery processing needs to occur asynchronously | ||
28 | * in a normal kernel context and not an interrupt context. | ||
29 | * This pair of routines creates an event and queues it onto a | ||
30 | * work-queue, where a worker thread can drive recovery. | ||
31 | */ | ||
32 | |||
33 | /* EEH event workqueue setup. */ | ||
34 | static spinlock_t eeh_eventlist_lock = SPIN_LOCK_UNLOCKED; | ||
35 | LIST_HEAD(eeh_eventlist); | ||
36 | static void eeh_thread_launcher(void *); | ||
37 | DECLARE_WORK(eeh_event_wq, eeh_thread_launcher, NULL); | ||
38 | |||
39 | /** | ||
40 | * eeh_panic - call panic() for an eeh event that cannot be handled. | ||
41 | * The philosophy of this routine is that it is better to panic and | ||
42 | * halt the OS than it is to risk possible data corruption by | ||
43 | * oblivious device drivers that don't know better. | ||
44 | * | ||
45 | * @dev pci device that had an eeh event | ||
46 | * @reset_state current reset state of the device slot | ||
47 | */ | ||
48 | static void eeh_panic(struct pci_dev *dev, int reset_state) | ||
49 | { | ||
50 | /* | ||
51 | * Since the panic_on_oops sysctl is used to halt the system | ||
52 | * in light of potential corruption, we can use it here. | ||
53 | */ | ||
54 | if (panic_on_oops) { | ||
55 | panic("EEH: MMIO failure (%d) on device:%s\n", reset_state, | ||
56 | pci_name(dev)); | ||
57 | } | ||
58 | else { | ||
59 | printk(KERN_INFO "EEH: Ignored MMIO failure (%d) on device:%s\n", | ||
60 | reset_state, pci_name(dev)); | ||
61 | } | ||
62 | } | ||
63 | |||
64 | /** | ||
65 | * eeh_event_handler - dispatch EEH events. The detection of a frozen | ||
66 | * slot can occur inside an interrupt, where it can be hard to do | ||
67 | * anything about it. The goal of this routine is to pull these | ||
68 | * detection events out of the context of the interrupt handler, and | ||
69 | * re-dispatch them for processing at a later time in a normal context. | ||
70 | * | ||
71 | * @dummy - unused | ||
72 | */ | ||
73 | static int eeh_event_handler(void * dummy) | ||
74 | { | ||
75 | unsigned long flags; | ||
76 | struct eeh_event *event; | ||
77 | |||
78 | daemonize ("eehd"); | ||
79 | |||
80 | while (1) { | ||
81 | set_current_state(TASK_INTERRUPTIBLE); | ||
82 | |||
83 | spin_lock_irqsave(&eeh_eventlist_lock, flags); | ||
84 | event = NULL; | ||
85 | if (!list_empty(&eeh_eventlist)) { | ||
86 | event = list_entry(eeh_eventlist.next, struct eeh_event, list); | ||
87 | list_del(&event->list); | ||
88 | } | ||
89 | spin_unlock_irqrestore(&eeh_eventlist_lock, flags); | ||
90 | if (event == NULL) | ||
91 | break; | ||
92 | |||
93 | printk(KERN_INFO "EEH: Detected PCI bus error on device %s\n", | ||
94 | pci_name(event->dev)); | ||
95 | |||
96 | eeh_panic (event->dev, event->state); | ||
97 | |||
98 | kfree(event); | ||
99 | } | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | /** | ||
105 | * eeh_thread_launcher | ||
106 | * | ||
107 | * @dummy - unused | ||
108 | */ | ||
109 | static void eeh_thread_launcher(void *dummy) | ||
110 | { | ||
111 | if (kernel_thread(eeh_event_handler, NULL, CLONE_KERNEL) < 0) | ||
112 | printk(KERN_ERR "Failed to start EEH daemon\n"); | ||
113 | } | ||
114 | |||
115 | /** | ||
116 | * eeh_send_failure_event - generate a PCI error event | ||
117 | * @dev pci device | ||
118 | * | ||
119 | * This routine can be called within an interrupt context; | ||
120 | * the actual event will be delivered in a normal context | ||
121 | * (from a workqueue). | ||
122 | */ | ||
123 | int eeh_send_failure_event (struct device_node *dn, | ||
124 | struct pci_dev *dev, | ||
125 | int state, | ||
126 | int time_unavail) | ||
127 | { | ||
128 | unsigned long flags; | ||
129 | struct eeh_event *event; | ||
130 | |||
131 | event = kmalloc(sizeof(*event), GFP_ATOMIC); | ||
132 | if (event == NULL) { | ||
133 | printk (KERN_ERR "EEH: out of memory, event not handled\n"); | ||
134 | return 1; | ||
135 | } | ||
136 | |||
137 | if (dev) | ||
138 | pci_dev_get(dev); | ||
139 | |||
140 | event->dn = dn; | ||
141 | event->dev = dev; | ||
142 | event->state = state; | ||
143 | event->time_unavail = time_unavail; | ||
144 | |||
145 | /* We may or may not be called in an interrupt context */ | ||
146 | spin_lock_irqsave(&eeh_eventlist_lock, flags); | ||
147 | list_add(&event->list, &eeh_eventlist); | ||
148 | spin_unlock_irqrestore(&eeh_eventlist_lock, flags); | ||
149 | |||
150 | schedule_work(&eeh_event_wq); | ||
151 | |||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | /********************** END OF FILE ******************************/ | ||
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index fcc50bfd43fd..97ba5214417f 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c | |||
@@ -42,7 +42,6 @@ | |||
42 | #include <asm/machdep.h> | 42 | #include <asm/machdep.h> |
43 | #include <asm/abs_addr.h> | 43 | #include <asm/abs_addr.h> |
44 | #include <asm/pSeries_reconfig.h> | 44 | #include <asm/pSeries_reconfig.h> |
45 | #include <asm/systemcfg.h> | ||
46 | #include <asm/firmware.h> | 45 | #include <asm/firmware.h> |
47 | #include <asm/tce.h> | 46 | #include <asm/tce.h> |
48 | #include <asm/ppc-pci.h> | 47 | #include <asm/ppc-pci.h> |
@@ -582,7 +581,7 @@ void iommu_init_early_pSeries(void) | |||
582 | return; | 581 | return; |
583 | } | 582 | } |
584 | 583 | ||
585 | if (systemcfg->platform & PLATFORM_LPAR) { | 584 | if (platform_is_lpar()) { |
586 | if (firmware_has_feature(FW_FEATURE_MULTITCE)) { | 585 | if (firmware_has_feature(FW_FEATURE_MULTITCE)) { |
587 | ppc_md.tce_build = tce_buildmulti_pSeriesLP; | 586 | ppc_md.tce_build = tce_buildmulti_pSeriesLP; |
588 | ppc_md.tce_free = tce_freemulti_pSeriesLP; | 587 | ppc_md.tce_free = tce_freemulti_pSeriesLP; |
diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c index c198656a3bb5..999a9620b5ce 100644 --- a/arch/powerpc/platforms/pseries/pci.c +++ b/arch/powerpc/platforms/pseries/pci.c | |||
@@ -107,7 +107,6 @@ static void __init pSeries_request_regions(void) | |||
107 | 107 | ||
108 | void __init pSeries_final_fixup(void) | 108 | void __init pSeries_final_fixup(void) |
109 | { | 109 | { |
110 | phbs_remap_io(); | ||
111 | pSeries_request_regions(); | 110 | pSeries_request_regions(); |
112 | 111 | ||
113 | pci_addr_cache_build(); | 112 | pci_addr_cache_build(); |
@@ -123,7 +122,7 @@ static void fixup_winbond_82c105(struct pci_dev* dev) | |||
123 | int i; | 122 | int i; |
124 | unsigned int reg; | 123 | unsigned int reg; |
125 | 124 | ||
126 | if (!(systemcfg->platform & PLATFORM_PSERIES)) | 125 | if (!platform_is_pseries()) |
127 | return; | 126 | return; |
128 | 127 | ||
129 | printk("Using INTC for W82c105 IDE controller.\n"); | 128 | printk("Using INTC for W82c105 IDE controller.\n"); |
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index d7d400339458..d8864164dbe8 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c | |||
@@ -408,7 +408,7 @@ static int proc_ppc64_create_ofdt(void) | |||
408 | { | 408 | { |
409 | struct proc_dir_entry *ent; | 409 | struct proc_dir_entry *ent; |
410 | 410 | ||
411 | if (!(systemcfg->platform & PLATFORM_PSERIES)) | 411 | if (!platform_is_pseries()) |
412 | return 0; | 412 | return 0; |
413 | 413 | ||
414 | ent = create_proc_entry("ppc64/ofdt", S_IWUSR, NULL); | 414 | ent = create_proc_entry("ppc64/ofdt", S_IWUSR, NULL); |
diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c index e26b0420b6dd..00cf331a1dc4 100644 --- a/arch/powerpc/platforms/pseries/rtasd.c +++ b/arch/powerpc/platforms/pseries/rtasd.c | |||
@@ -482,10 +482,12 @@ static int __init rtas_init(void) | |||
482 | { | 482 | { |
483 | struct proc_dir_entry *entry; | 483 | struct proc_dir_entry *entry; |
484 | 484 | ||
485 | /* No RTAS, only warn if we are on a pSeries box */ | 485 | if (!platform_is_pseries()) |
486 | return 0; | ||
487 | |||
488 | /* No RTAS */ | ||
486 | if (rtas_token("event-scan") == RTAS_UNKNOWN_SERVICE) { | 489 | if (rtas_token("event-scan") == RTAS_UNKNOWN_SERVICE) { |
487 | if (systemcfg->platform & PLATFORM_PSERIES) | 490 | printk(KERN_INFO "rtasd: no event-scan on system\n"); |
488 | printk(KERN_INFO "rtasd: no event-scan on system\n"); | ||
489 | return 1; | 491 | return 1; |
490 | } | 492 | } |
491 | 493 | ||
diff --git a/arch/ppc64/kernel/scanlog.c b/arch/powerpc/platforms/pseries/scanlog.c index 2edc947f7c44..2edc947f7c44 100644 --- a/arch/ppc64/kernel/scanlog.c +++ b/arch/powerpc/platforms/pseries/scanlog.c | |||
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index a093a0d4dd69..e94247c28d42 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c | |||
@@ -249,7 +249,7 @@ static void __init pSeries_setup_arch(void) | |||
249 | ppc_md.idle_loop = default_idle; | 249 | ppc_md.idle_loop = default_idle; |
250 | } | 250 | } |
251 | 251 | ||
252 | if (systemcfg->platform & PLATFORM_LPAR) | 252 | if (platform_is_lpar()) |
253 | ppc_md.enable_pmcs = pseries_lpar_enable_pmcs; | 253 | ppc_md.enable_pmcs = pseries_lpar_enable_pmcs; |
254 | else | 254 | else |
255 | ppc_md.enable_pmcs = power4_enable_pmcs; | 255 | ppc_md.enable_pmcs = power4_enable_pmcs; |
@@ -378,7 +378,7 @@ static void __init pSeries_init_early(void) | |||
378 | 378 | ||
379 | fw_feature_init(); | 379 | fw_feature_init(); |
380 | 380 | ||
381 | if (systemcfg->platform & PLATFORM_LPAR) | 381 | if (platform_is_lpar()) |
382 | hpte_init_lpar(); | 382 | hpte_init_lpar(); |
383 | else { | 383 | else { |
384 | hpte_init_native(); | 384 | hpte_init_native(); |
@@ -388,7 +388,7 @@ static void __init pSeries_init_early(void) | |||
388 | 388 | ||
389 | generic_find_legacy_serial_ports(&physport, &default_speed); | 389 | generic_find_legacy_serial_ports(&physport, &default_speed); |
390 | 390 | ||
391 | if (systemcfg->platform & PLATFORM_LPAR) | 391 | if (platform_is_lpar()) |
392 | find_udbg_vterm(); | 392 | find_udbg_vterm(); |
393 | else if (physport) { | 393 | else if (physport) { |
394 | /* Map the uart for udbg. */ | 394 | /* Map the uart for udbg. */ |
@@ -592,7 +592,7 @@ static void pseries_shared_idle(void) | |||
592 | 592 | ||
593 | static int pSeries_pci_probe_mode(struct pci_bus *bus) | 593 | static int pSeries_pci_probe_mode(struct pci_bus *bus) |
594 | { | 594 | { |
595 | if (systemcfg->platform & PLATFORM_LPAR) | 595 | if (platform_is_lpar()) |
596 | return PCI_PROBE_DEVTREE; | 596 | return PCI_PROBE_DEVTREE; |
597 | return PCI_PROBE_NORMAL; | 597 | return PCI_PROBE_NORMAL; |
598 | } | 598 | } |
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index 7a243e8ccd7e..3ba794ca3288 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <asm/rtas.h> | 46 | #include <asm/rtas.h> |
47 | #include <asm/pSeries_reconfig.h> | 47 | #include <asm/pSeries_reconfig.h> |
48 | #include <asm/mpic.h> | 48 | #include <asm/mpic.h> |
49 | #include <asm/systemcfg.h> | ||
49 | 50 | ||
50 | #include "plpar_wrappers.h" | 51 | #include "plpar_wrappers.h" |
51 | 52 | ||
@@ -96,7 +97,7 @@ int pSeries_cpu_disable(void) | |||
96 | int cpu = smp_processor_id(); | 97 | int cpu = smp_processor_id(); |
97 | 98 | ||
98 | cpu_clear(cpu, cpu_online_map); | 99 | cpu_clear(cpu, cpu_online_map); |
99 | systemcfg->processorCount--; | 100 | _systemcfg->processorCount--; |
100 | 101 | ||
101 | /*fix boot_cpuid here*/ | 102 | /*fix boot_cpuid here*/ |
102 | if (cpu == boot_cpuid) | 103 | if (cpu == boot_cpuid) |
@@ -441,7 +442,7 @@ void __init smp_init_pSeries(void) | |||
441 | smp_ops->cpu_die = pSeries_cpu_die; | 442 | smp_ops->cpu_die = pSeries_cpu_die; |
442 | 443 | ||
443 | /* Processors can be added/removed only on LPAR */ | 444 | /* Processors can be added/removed only on LPAR */ |
444 | if (systemcfg->platform == PLATFORM_PSERIES_LPAR) | 445 | if (platform_is_lpar()) |
445 | pSeries_reconfig_notifier_register(&pSeries_smp_nb); | 446 | pSeries_reconfig_notifier_register(&pSeries_smp_nb); |
446 | #endif | 447 | #endif |
447 | 448 | ||
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index c72c86f05cb6..72ac18067ece 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c | |||
@@ -545,7 +545,9 @@ nextnode: | |||
545 | of_node_put(np); | 545 | of_node_put(np); |
546 | } | 546 | } |
547 | 547 | ||
548 | if (systemcfg->platform == PLATFORM_PSERIES) { | 548 | if (platform_is_lpar()) |
549 | ops = &pSeriesLP_ops; | ||
550 | else { | ||
549 | #ifdef CONFIG_SMP | 551 | #ifdef CONFIG_SMP |
550 | for_each_cpu(i) { | 552 | for_each_cpu(i) { |
551 | int hard_id; | 553 | int hard_id; |
@@ -561,12 +563,11 @@ nextnode: | |||
561 | #else | 563 | #else |
562 | xics_per_cpu[0] = ioremap(intr_base, intr_size); | 564 | xics_per_cpu[0] = ioremap(intr_base, intr_size); |
563 | #endif /* CONFIG_SMP */ | 565 | #endif /* CONFIG_SMP */ |
564 | } else if (systemcfg->platform == PLATFORM_PSERIES_LPAR) { | ||
565 | ops = &pSeriesLP_ops; | ||
566 | } | 566 | } |
567 | 567 | ||
568 | xics_8259_pic.enable = i8259_pic.enable; | 568 | xics_8259_pic.enable = i8259_pic.enable; |
569 | xics_8259_pic.disable = i8259_pic.disable; | 569 | xics_8259_pic.disable = i8259_pic.disable; |
570 | xics_8259_pic.end = i8259_pic.end; | ||
570 | for (i = 0; i < 16; ++i) | 571 | for (i = 0; i < 16; ++i) |
571 | get_irq_desc(i)->handler = &xics_8259_pic; | 572 | get_irq_desc(i)->handler = &xics_8259_pic; |
572 | for (; i < NR_IRQS; ++i) | 573 | for (; i < NR_IRQS; ++i) |
diff --git a/arch/powerpc/sysdev/u3_iommu.c b/arch/powerpc/sysdev/u3_iommu.c index 543d65909812..f32baf7f4693 100644 --- a/arch/powerpc/sysdev/u3_iommu.c +++ b/arch/powerpc/sysdev/u3_iommu.c | |||
@@ -226,7 +226,7 @@ static void iommu_table_u3_setup(void) | |||
226 | iommu_table_u3.it_busno = 0; | 226 | iommu_table_u3.it_busno = 0; |
227 | iommu_table_u3.it_offset = 0; | 227 | iommu_table_u3.it_offset = 0; |
228 | /* it_size is in number of entries */ | 228 | /* it_size is in number of entries */ |
229 | iommu_table_u3.it_size = dart_tablesize / sizeof(u32); | 229 | iommu_table_u3.it_size = (dart_tablesize / sizeof(u32)) >> DART_PAGE_FACTOR; |
230 | 230 | ||
231 | /* Initialize the common IOMMU code */ | 231 | /* Initialize the common IOMMU code */ |
232 | iommu_table_u3.it_base = (unsigned long)dart_vbase; | 232 | iommu_table_u3.it_base = (unsigned long)dart_vbase; |
diff --git a/arch/powerpc/xmon/Makefile b/arch/powerpc/xmon/Makefile index 79a784f0e7a9..b20312e5ed27 100644 --- a/arch/powerpc/xmon/Makefile +++ b/arch/powerpc/xmon/Makefile | |||
@@ -8,4 +8,4 @@ obj-$(CONFIG_8xx) += start_8xx.o | |||
8 | obj-$(CONFIG_6xx) += start_32.o | 8 | obj-$(CONFIG_6xx) += start_32.o |
9 | obj-$(CONFIG_4xx) += start_32.o | 9 | obj-$(CONFIG_4xx) += start_32.o |
10 | obj-$(CONFIG_PPC64) += start_64.o | 10 | obj-$(CONFIG_PPC64) += start_64.o |
11 | obj-y += xmon.o ppc-dis.o ppc-opc.o subr_prf.o setjmp.o | 11 | obj-y += xmon.o ppc-dis.o ppc-opc.o setjmp.o nonstdio.o |
diff --git a/arch/powerpc/xmon/nonstdio.c b/arch/powerpc/xmon/nonstdio.c new file mode 100644 index 000000000000..78765833f4c0 --- /dev/null +++ b/arch/powerpc/xmon/nonstdio.c | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1996-2005 Paul Mackerras. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | */ | ||
9 | #include <linux/string.h> | ||
10 | #include <asm/time.h> | ||
11 | #include "nonstdio.h" | ||
12 | |||
13 | int xmon_putchar(int c) | ||
14 | { | ||
15 | char ch = c; | ||
16 | |||
17 | if (c == '\n') | ||
18 | xmon_putchar('\r'); | ||
19 | return xmon_write(&ch, 1) == 1? c: -1; | ||
20 | } | ||
21 | |||
22 | static char line[256]; | ||
23 | static char *lineptr; | ||
24 | static int lineleft; | ||
25 | |||
26 | int xmon_expect(const char *str, unsigned long timeout) | ||
27 | { | ||
28 | int c; | ||
29 | unsigned long t0; | ||
30 | |||
31 | /* assume 25MHz default timebase if tb_ticks_per_sec not set yet */ | ||
32 | timeout *= tb_ticks_per_sec? tb_ticks_per_sec: 25000000; | ||
33 | t0 = get_tbl(); | ||
34 | do { | ||
35 | lineptr = line; | ||
36 | for (;;) { | ||
37 | c = xmon_read_poll(); | ||
38 | if (c == -1) { | ||
39 | if (get_tbl() - t0 > timeout) | ||
40 | return 0; | ||
41 | continue; | ||
42 | } | ||
43 | if (c == '\n') | ||
44 | break; | ||
45 | if (c != '\r' && lineptr < &line[sizeof(line) - 1]) | ||
46 | *lineptr++ = c; | ||
47 | } | ||
48 | *lineptr = 0; | ||
49 | } while (strstr(line, str) == NULL); | ||
50 | return 1; | ||
51 | } | ||
52 | |||
53 | int xmon_getchar(void) | ||
54 | { | ||
55 | int c; | ||
56 | |||
57 | if (lineleft == 0) { | ||
58 | lineptr = line; | ||
59 | for (;;) { | ||
60 | c = xmon_readchar(); | ||
61 | if (c == -1 || c == 4) | ||
62 | break; | ||
63 | if (c == '\r' || c == '\n') { | ||
64 | *lineptr++ = '\n'; | ||
65 | xmon_putchar('\n'); | ||
66 | break; | ||
67 | } | ||
68 | switch (c) { | ||
69 | case 0177: | ||
70 | case '\b': | ||
71 | if (lineptr > line) { | ||
72 | xmon_putchar('\b'); | ||
73 | xmon_putchar(' '); | ||
74 | xmon_putchar('\b'); | ||
75 | --lineptr; | ||
76 | } | ||
77 | break; | ||
78 | case 'U' & 0x1F: | ||
79 | while (lineptr > line) { | ||
80 | xmon_putchar('\b'); | ||
81 | xmon_putchar(' '); | ||
82 | xmon_putchar('\b'); | ||
83 | --lineptr; | ||
84 | } | ||
85 | break; | ||
86 | default: | ||
87 | if (lineptr >= &line[sizeof(line) - 1]) | ||
88 | xmon_putchar('\a'); | ||
89 | else { | ||
90 | xmon_putchar(c); | ||
91 | *lineptr++ = c; | ||
92 | } | ||
93 | } | ||
94 | } | ||
95 | lineleft = lineptr - line; | ||
96 | lineptr = line; | ||
97 | } | ||
98 | if (lineleft == 0) | ||
99 | return -1; | ||
100 | --lineleft; | ||
101 | return *lineptr++; | ||
102 | } | ||
103 | |||
104 | char *xmon_gets(char *str, int nb) | ||
105 | { | ||
106 | char *p; | ||
107 | int c; | ||
108 | |||
109 | for (p = str; p < str + nb - 1; ) { | ||
110 | c = xmon_getchar(); | ||
111 | if (c == -1) { | ||
112 | if (p == str) | ||
113 | return NULL; | ||
114 | break; | ||
115 | } | ||
116 | *p++ = c; | ||
117 | if (c == '\n') | ||
118 | break; | ||
119 | } | ||
120 | *p = 0; | ||
121 | return str; | ||
122 | } | ||
123 | |||
124 | void xmon_printf(const char *format, ...) | ||
125 | { | ||
126 | va_list args; | ||
127 | int n; | ||
128 | static char xmon_outbuf[1024]; | ||
129 | |||
130 | va_start(args, format); | ||
131 | n = vsnprintf(xmon_outbuf, sizeof(xmon_outbuf), format, args); | ||
132 | va_end(args); | ||
133 | xmon_write(xmon_outbuf, n); | ||
134 | } | ||
diff --git a/arch/powerpc/xmon/nonstdio.h b/arch/powerpc/xmon/nonstdio.h index 84211a21c6f4..47cebbd2b1b1 100644 --- a/arch/powerpc/xmon/nonstdio.h +++ b/arch/powerpc/xmon/nonstdio.h | |||
@@ -1,22 +1,14 @@ | |||
1 | typedef int FILE; | ||
2 | extern FILE *xmon_stdin, *xmon_stdout; | ||
3 | #define EOF (-1) | 1 | #define EOF (-1) |
4 | #define stdin xmon_stdin | 2 | |
5 | #define stdout xmon_stdout | ||
6 | #define printf xmon_printf | 3 | #define printf xmon_printf |
7 | #define fprintf xmon_fprintf | ||
8 | #define fputs xmon_fputs | ||
9 | #define fgets xmon_fgets | ||
10 | #define putchar xmon_putchar | 4 | #define putchar xmon_putchar |
11 | #define getchar xmon_getchar | ||
12 | #define putc xmon_putc | ||
13 | #define getc xmon_getc | ||
14 | #define fopen(n, m) NULL | ||
15 | #define fflush(f) do {} while (0) | ||
16 | #define fclose(f) do {} while (0) | ||
17 | extern char *fgets(char *, int, void *); | ||
18 | extern void xmon_printf(const char *, ...); | ||
19 | extern void xmon_fprintf(void *, const char *, ...); | ||
20 | extern void xmon_sprintf(char *, const char *, ...); | ||
21 | 5 | ||
22 | #define perror(s) printf("%s: no files!\n", (s)) | 6 | extern int xmon_putchar(int c); |
7 | extern int xmon_getchar(void); | ||
8 | extern char *xmon_gets(char *, int); | ||
9 | extern void xmon_printf(const char *, ...); | ||
10 | extern void xmon_map_scc(void); | ||
11 | extern int xmon_expect(const char *str, unsigned long timeout); | ||
12 | extern int xmon_write(void *ptr, int nb); | ||
13 | extern int xmon_readchar(void); | ||
14 | extern int xmon_read_poll(void); | ||
diff --git a/arch/powerpc/xmon/setjmp.S b/arch/powerpc/xmon/setjmp.S index f8e40dfd2bff..96a91f10e2ec 100644 --- a/arch/powerpc/xmon/setjmp.S +++ b/arch/powerpc/xmon/setjmp.S | |||
@@ -14,61 +14,61 @@ | |||
14 | 14 | ||
15 | _GLOBAL(xmon_setjmp) | 15 | _GLOBAL(xmon_setjmp) |
16 | mflr r0 | 16 | mflr r0 |
17 | STL r0,0(r3) | 17 | PPC_STL r0,0(r3) |
18 | STL r1,SZL(r3) | 18 | PPC_STL r1,SZL(r3) |
19 | STL r2,2*SZL(r3) | 19 | PPC_STL r2,2*SZL(r3) |
20 | mfcr r0 | 20 | mfcr r0 |
21 | STL r0,3*SZL(r3) | 21 | PPC_STL r0,3*SZL(r3) |
22 | STL r13,4*SZL(r3) | 22 | PPC_STL r13,4*SZL(r3) |
23 | STL r14,5*SZL(r3) | 23 | PPC_STL r14,5*SZL(r3) |
24 | STL r15,6*SZL(r3) | 24 | PPC_STL r15,6*SZL(r3) |
25 | STL r16,7*SZL(r3) | 25 | PPC_STL r16,7*SZL(r3) |
26 | STL r17,8*SZL(r3) | 26 | PPC_STL r17,8*SZL(r3) |
27 | STL r18,9*SZL(r3) | 27 | PPC_STL r18,9*SZL(r3) |
28 | STL r19,10*SZL(r3) | 28 | PPC_STL r19,10*SZL(r3) |
29 | STL r20,11*SZL(r3) | 29 | PPC_STL r20,11*SZL(r3) |
30 | STL r21,12*SZL(r3) | 30 | PPC_STL r21,12*SZL(r3) |
31 | STL r22,13*SZL(r3) | 31 | PPC_STL r22,13*SZL(r3) |
32 | STL r23,14*SZL(r3) | 32 | PPC_STL r23,14*SZL(r3) |
33 | STL r24,15*SZL(r3) | 33 | PPC_STL r24,15*SZL(r3) |
34 | STL r25,16*SZL(r3) | 34 | PPC_STL r25,16*SZL(r3) |
35 | STL r26,17*SZL(r3) | 35 | PPC_STL r26,17*SZL(r3) |
36 | STL r27,18*SZL(r3) | 36 | PPC_STL r27,18*SZL(r3) |
37 | STL r28,19*SZL(r3) | 37 | PPC_STL r28,19*SZL(r3) |
38 | STL r29,20*SZL(r3) | 38 | PPC_STL r29,20*SZL(r3) |
39 | STL r30,21*SZL(r3) | 39 | PPC_STL r30,21*SZL(r3) |
40 | STL r31,22*SZL(r3) | 40 | PPC_STL r31,22*SZL(r3) |
41 | li r3,0 | 41 | li r3,0 |
42 | blr | 42 | blr |
43 | 43 | ||
44 | _GLOBAL(xmon_longjmp) | 44 | _GLOBAL(xmon_longjmp) |
45 | CMPI r4,0 | 45 | PPC_LCMPI r4,0 |
46 | bne 1f | 46 | bne 1f |
47 | li r4,1 | 47 | li r4,1 |
48 | 1: LDL r13,4*SZL(r3) | 48 | 1: PPC_LL r13,4*SZL(r3) |
49 | LDL r14,5*SZL(r3) | 49 | PPC_LL r14,5*SZL(r3) |
50 | LDL r15,6*SZL(r3) | 50 | PPC_LL r15,6*SZL(r3) |
51 | LDL r16,7*SZL(r3) | 51 | PPC_LL r16,7*SZL(r3) |
52 | LDL r17,8*SZL(r3) | 52 | PPC_LL r17,8*SZL(r3) |
53 | LDL r18,9*SZL(r3) | 53 | PPC_LL r18,9*SZL(r3) |
54 | LDL r19,10*SZL(r3) | 54 | PPC_LL r19,10*SZL(r3) |
55 | LDL r20,11*SZL(r3) | 55 | PPC_LL r20,11*SZL(r3) |
56 | LDL r21,12*SZL(r3) | 56 | PPC_LL r21,12*SZL(r3) |
57 | LDL r22,13*SZL(r3) | 57 | PPC_LL r22,13*SZL(r3) |
58 | LDL r23,14*SZL(r3) | 58 | PPC_LL r23,14*SZL(r3) |
59 | LDL r24,15*SZL(r3) | 59 | PPC_LL r24,15*SZL(r3) |
60 | LDL r25,16*SZL(r3) | 60 | PPC_LL r25,16*SZL(r3) |
61 | LDL r26,17*SZL(r3) | 61 | PPC_LL r26,17*SZL(r3) |
62 | LDL r27,18*SZL(r3) | 62 | PPC_LL r27,18*SZL(r3) |
63 | LDL r28,19*SZL(r3) | 63 | PPC_LL r28,19*SZL(r3) |
64 | LDL r29,20*SZL(r3) | 64 | PPC_LL r29,20*SZL(r3) |
65 | LDL r30,21*SZL(r3) | 65 | PPC_LL r30,21*SZL(r3) |
66 | LDL r31,22*SZL(r3) | 66 | PPC_LL r31,22*SZL(r3) |
67 | LDL r0,3*SZL(r3) | 67 | PPC_LL r0,3*SZL(r3) |
68 | mtcrf 0x38,r0 | 68 | mtcrf 0x38,r0 |
69 | LDL r0,0(r3) | 69 | PPC_LL r0,0(r3) |
70 | LDL r1,SZL(r3) | 70 | PPC_LL r1,SZL(r3) |
71 | LDL r2,2*SZL(r3) | 71 | PPC_LL r2,2*SZL(r3) |
72 | mtlr r0 | 72 | mtlr r0 |
73 | mr r3,r4 | 73 | mr r3,r4 |
74 | blr | 74 | blr |
@@ -84,52 +84,52 @@ _GLOBAL(xmon_longjmp) | |||
84 | * different ABIs, though). | 84 | * different ABIs, though). |
85 | */ | 85 | */ |
86 | _GLOBAL(xmon_save_regs) | 86 | _GLOBAL(xmon_save_regs) |
87 | STL r0,0*SZL(r3) | 87 | PPC_STL r0,0*SZL(r3) |
88 | STL r2,2*SZL(r3) | 88 | PPC_STL r2,2*SZL(r3) |
89 | STL r3,3*SZL(r3) | 89 | PPC_STL r3,3*SZL(r3) |
90 | STL r4,4*SZL(r3) | 90 | PPC_STL r4,4*SZL(r3) |
91 | STL r5,5*SZL(r3) | 91 | PPC_STL r5,5*SZL(r3) |
92 | STL r6,6*SZL(r3) | 92 | PPC_STL r6,6*SZL(r3) |
93 | STL r7,7*SZL(r3) | 93 | PPC_STL r7,7*SZL(r3) |
94 | STL r8,8*SZL(r3) | 94 | PPC_STL r8,8*SZL(r3) |
95 | STL r9,9*SZL(r3) | 95 | PPC_STL r9,9*SZL(r3) |
96 | STL r10,10*SZL(r3) | 96 | PPC_STL r10,10*SZL(r3) |
97 | STL r11,11*SZL(r3) | 97 | PPC_STL r11,11*SZL(r3) |
98 | STL r12,12*SZL(r3) | 98 | PPC_STL r12,12*SZL(r3) |
99 | STL r13,13*SZL(r3) | 99 | PPC_STL r13,13*SZL(r3) |
100 | STL r14,14*SZL(r3) | 100 | PPC_STL r14,14*SZL(r3) |
101 | STL r15,15*SZL(r3) | 101 | PPC_STL r15,15*SZL(r3) |
102 | STL r16,16*SZL(r3) | 102 | PPC_STL r16,16*SZL(r3) |
103 | STL r17,17*SZL(r3) | 103 | PPC_STL r17,17*SZL(r3) |
104 | STL r18,18*SZL(r3) | 104 | PPC_STL r18,18*SZL(r3) |
105 | STL r19,19*SZL(r3) | 105 | PPC_STL r19,19*SZL(r3) |
106 | STL r20,20*SZL(r3) | 106 | PPC_STL r20,20*SZL(r3) |
107 | STL r21,21*SZL(r3) | 107 | PPC_STL r21,21*SZL(r3) |
108 | STL r22,22*SZL(r3) | 108 | PPC_STL r22,22*SZL(r3) |
109 | STL r23,23*SZL(r3) | 109 | PPC_STL r23,23*SZL(r3) |
110 | STL r24,24*SZL(r3) | 110 | PPC_STL r24,24*SZL(r3) |
111 | STL r25,25*SZL(r3) | 111 | PPC_STL r25,25*SZL(r3) |
112 | STL r26,26*SZL(r3) | 112 | PPC_STL r26,26*SZL(r3) |
113 | STL r27,27*SZL(r3) | 113 | PPC_STL r27,27*SZL(r3) |
114 | STL r28,28*SZL(r3) | 114 | PPC_STL r28,28*SZL(r3) |
115 | STL r29,29*SZL(r3) | 115 | PPC_STL r29,29*SZL(r3) |
116 | STL r30,30*SZL(r3) | 116 | PPC_STL r30,30*SZL(r3) |
117 | STL r31,31*SZL(r3) | 117 | PPC_STL r31,31*SZL(r3) |
118 | /* go up one stack frame for SP */ | 118 | /* go up one stack frame for SP */ |
119 | LDL r4,0(r1) | 119 | PPC_LL r4,0(r1) |
120 | STL r4,1*SZL(r3) | 120 | PPC_STL r4,1*SZL(r3) |
121 | /* get caller's LR */ | 121 | /* get caller's LR */ |
122 | LDL r0,LRSAVE(r4) | 122 | PPC_LL r0,LRSAVE(r4) |
123 | STL r0,_NIP-STACK_FRAME_OVERHEAD(r3) | 123 | PPC_STL r0,_NIP-STACK_FRAME_OVERHEAD(r3) |
124 | STL r0,_LINK-STACK_FRAME_OVERHEAD(r3) | 124 | PPC_STL r0,_LINK-STACK_FRAME_OVERHEAD(r3) |
125 | mfmsr r0 | 125 | mfmsr r0 |
126 | STL r0,_MSR-STACK_FRAME_OVERHEAD(r3) | 126 | PPC_STL r0,_MSR-STACK_FRAME_OVERHEAD(r3) |
127 | mfctr r0 | 127 | mfctr r0 |
128 | STL r0,_CTR-STACK_FRAME_OVERHEAD(r3) | 128 | PPC_STL r0,_CTR-STACK_FRAME_OVERHEAD(r3) |
129 | mfxer r0 | 129 | mfxer r0 |
130 | STL r0,_XER-STACK_FRAME_OVERHEAD(r3) | 130 | PPC_STL r0,_XER-STACK_FRAME_OVERHEAD(r3) |
131 | mfcr r0 | 131 | mfcr r0 |
132 | STL r0,_CCR-STACK_FRAME_OVERHEAD(r3) | 132 | PPC_STL r0,_CCR-STACK_FRAME_OVERHEAD(r3) |
133 | li r0,0 | 133 | li r0,0 |
134 | STL r0,_TRAP-STACK_FRAME_OVERHEAD(r3) | 134 | PPC_STL r0,_TRAP-STACK_FRAME_OVERHEAD(r3) |
135 | blr | 135 | blr |
diff --git a/arch/powerpc/xmon/start_32.c b/arch/powerpc/xmon/start_32.c index 69b658c0f760..c2464df4217e 100644 --- a/arch/powerpc/xmon/start_32.c +++ b/arch/powerpc/xmon/start_32.c | |||
@@ -11,7 +11,6 @@ | |||
11 | #include <linux/cuda.h> | 11 | #include <linux/cuda.h> |
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/errno.h> | 13 | #include <linux/errno.h> |
14 | #include <linux/sysrq.h> | ||
15 | #include <linux/bitops.h> | 14 | #include <linux/bitops.h> |
16 | #include <asm/xmon.h> | 15 | #include <asm/xmon.h> |
17 | #include <asm/prom.h> | 16 | #include <asm/prom.h> |
@@ -22,10 +21,11 @@ | |||
22 | #include <asm/processor.h> | 21 | #include <asm/processor.h> |
23 | #include <asm/delay.h> | 22 | #include <asm/delay.h> |
24 | #include <asm/btext.h> | 23 | #include <asm/btext.h> |
24 | #include <asm/time.h> | ||
25 | #include "nonstdio.h" | ||
25 | 26 | ||
26 | static volatile unsigned char __iomem *sccc, *sccd; | 27 | static volatile unsigned char __iomem *sccc, *sccd; |
27 | unsigned int TXRDY, RXRDY, DLAB; | 28 | unsigned int TXRDY, RXRDY, DLAB; |
28 | static int xmon_expect(const char *str, unsigned int timeout); | ||
29 | 29 | ||
30 | static int use_serial; | 30 | static int use_serial; |
31 | static int use_screen; | 31 | static int use_screen; |
@@ -33,16 +33,6 @@ static int via_modem; | |||
33 | static int xmon_use_sccb; | 33 | static int xmon_use_sccb; |
34 | static struct device_node *channel_node; | 34 | static struct device_node *channel_node; |
35 | 35 | ||
36 | #define TB_SPEED 25000000 | ||
37 | |||
38 | static inline unsigned int readtb(void) | ||
39 | { | ||
40 | unsigned int ret; | ||
41 | |||
42 | asm volatile("mftb %0" : "=r" (ret) :); | ||
43 | return ret; | ||
44 | } | ||
45 | |||
46 | void buf_access(void) | 36 | void buf_access(void) |
47 | { | 37 | { |
48 | if (DLAB) | 38 | if (DLAB) |
@@ -91,23 +81,7 @@ static unsigned long chrp_find_phys_io_base(void) | |||
91 | } | 81 | } |
92 | #endif /* CONFIG_PPC_CHRP */ | 82 | #endif /* CONFIG_PPC_CHRP */ |
93 | 83 | ||
94 | #ifdef CONFIG_MAGIC_SYSRQ | 84 | void xmon_map_scc(void) |
95 | static void sysrq_handle_xmon(int key, struct pt_regs *regs, | ||
96 | struct tty_struct *tty) | ||
97 | { | ||
98 | xmon(regs); | ||
99 | } | ||
100 | |||
101 | static struct sysrq_key_op sysrq_xmon_op = | ||
102 | { | ||
103 | .handler = sysrq_handle_xmon, | ||
104 | .help_msg = "Xmon", | ||
105 | .action_msg = "Entering xmon", | ||
106 | }; | ||
107 | #endif | ||
108 | |||
109 | void | ||
110 | xmon_map_scc(void) | ||
111 | { | 85 | { |
112 | #ifdef CONFIG_PPC_MULTIPLATFORM | 86 | #ifdef CONFIG_PPC_MULTIPLATFORM |
113 | volatile unsigned char __iomem *base; | 87 | volatile unsigned char __iomem *base; |
@@ -217,8 +191,6 @@ xmon_map_scc(void) | |||
217 | RXRDY = 1; | 191 | RXRDY = 1; |
218 | DLAB = 0x80; | 192 | DLAB = 0x80; |
219 | #endif /* platform */ | 193 | #endif /* platform */ |
220 | |||
221 | register_sysrq_key('x', &sysrq_xmon_op); | ||
222 | } | 194 | } |
223 | 195 | ||
224 | static int scc_initialized = 0; | 196 | static int scc_initialized = 0; |
@@ -238,8 +210,7 @@ static inline void do_poll_adb(void) | |||
238 | #endif /* CONFIG_ADB_CUDA */ | 210 | #endif /* CONFIG_ADB_CUDA */ |
239 | } | 211 | } |
240 | 212 | ||
241 | int | 213 | int xmon_write(void *ptr, int nb) |
242 | xmon_write(void *handle, void *ptr, int nb) | ||
243 | { | 214 | { |
244 | char *p = ptr; | 215 | char *p = ptr; |
245 | int i, c, ct; | 216 | int i, c, ct; |
@@ -311,8 +282,7 @@ static unsigned char xmon_shift_keytab[128] = | |||
311 | "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */ | 282 | "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */ |
312 | "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */ | 283 | "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */ |
313 | 284 | ||
314 | static int | 285 | static int xmon_get_adb_key(void) |
315 | xmon_get_adb_key(void) | ||
316 | { | 286 | { |
317 | int k, t, on; | 287 | int k, t, on; |
318 | 288 | ||
@@ -350,32 +320,21 @@ xmon_get_adb_key(void) | |||
350 | } | 320 | } |
351 | #endif /* CONFIG_BOOTX_TEXT */ | 321 | #endif /* CONFIG_BOOTX_TEXT */ |
352 | 322 | ||
353 | int | 323 | int xmon_readchar(void) |
354 | xmon_read(void *handle, void *ptr, int nb) | ||
355 | { | 324 | { |
356 | char *p = ptr; | ||
357 | int i; | ||
358 | |||
359 | #ifdef CONFIG_BOOTX_TEXT | 325 | #ifdef CONFIG_BOOTX_TEXT |
360 | if (use_screen) { | 326 | if (use_screen) |
361 | for (i = 0; i < nb; ++i) | 327 | return xmon_get_adb_key(); |
362 | *p++ = xmon_get_adb_key(); | ||
363 | return i; | ||
364 | } | ||
365 | #endif | 328 | #endif |
366 | if (!scc_initialized) | 329 | if (!scc_initialized) |
367 | xmon_init_scc(); | 330 | xmon_init_scc(); |
368 | for (i = 0; i < nb; ++i) { | ||
369 | while ((*sccc & RXRDY) == 0) | 331 | while ((*sccc & RXRDY) == 0) |
370 | do_poll_adb(); | 332 | do_poll_adb(); |
371 | buf_access(); | 333 | buf_access(); |
372 | *p++ = *sccd; | 334 | return *sccd; |
373 | } | ||
374 | return i; | ||
375 | } | 335 | } |
376 | 336 | ||
377 | int | 337 | int xmon_read_poll(void) |
378 | xmon_read_poll(void) | ||
379 | { | 338 | { |
380 | if ((*sccc & RXRDY) == 0) { | 339 | if ((*sccc & RXRDY) == 0) { |
381 | do_poll_adb(); | 340 | do_poll_adb(); |
@@ -395,8 +354,7 @@ static unsigned char scc_inittab[] = { | |||
395 | 3, 0xc1, /* rx enable, 8 bits */ | 354 | 3, 0xc1, /* rx enable, 8 bits */ |
396 | }; | 355 | }; |
397 | 356 | ||
398 | void | 357 | void xmon_init_scc(void) |
399 | xmon_init_scc(void) | ||
400 | { | 358 | { |
401 | if ( _machine == _MACH_chrp ) | 359 | if ( _machine == _MACH_chrp ) |
402 | { | 360 | { |
@@ -410,6 +368,7 @@ xmon_init_scc(void) | |||
410 | else if ( _machine == _MACH_Pmac ) | 368 | else if ( _machine == _MACH_Pmac ) |
411 | { | 369 | { |
412 | int i, x; | 370 | int i, x; |
371 | unsigned long timeout; | ||
413 | 372 | ||
414 | if (channel_node != 0) | 373 | if (channel_node != 0) |
415 | pmac_call_feature( | 374 | pmac_call_feature( |
@@ -424,8 +383,12 @@ xmon_init_scc(void) | |||
424 | PMAC_FTR_MODEM_ENABLE, | 383 | PMAC_FTR_MODEM_ENABLE, |
425 | channel_node, 0, 1); | 384 | channel_node, 0, 1); |
426 | printk(KERN_INFO "Modem powered up by debugger !\n"); | 385 | printk(KERN_INFO "Modem powered up by debugger !\n"); |
427 | t0 = readtb(); | 386 | t0 = get_tbl(); |
428 | while (readtb() - t0 < 3*TB_SPEED) | 387 | timeout = 3 * tb_ticks_per_sec; |
388 | if (timeout == 0) | ||
389 | /* assume 25MHz if tb_ticks_per_sec not set */ | ||
390 | timeout = 75000000; | ||
391 | while (get_tbl() - t0 < timeout) | ||
429 | eieio(); | 392 | eieio(); |
430 | } | 393 | } |
431 | /* use the B channel if requested */ | 394 | /* use the B channel if requested */ |
@@ -447,164 +410,19 @@ xmon_init_scc(void) | |||
447 | scc_initialized = 1; | 410 | scc_initialized = 1; |
448 | if (via_modem) { | 411 | if (via_modem) { |
449 | for (;;) { | 412 | for (;;) { |
450 | xmon_write(NULL, "ATE1V1\r", 7); | 413 | xmon_write("ATE1V1\r", 7); |
451 | if (xmon_expect("OK", 5)) { | 414 | if (xmon_expect("OK", 5)) { |
452 | xmon_write(NULL, "ATA\r", 4); | 415 | xmon_write("ATA\r", 4); |
453 | if (xmon_expect("CONNECT", 40)) | 416 | if (xmon_expect("CONNECT", 40)) |
454 | break; | 417 | break; |
455 | } | 418 | } |
456 | xmon_write(NULL, "+++", 3); | 419 | xmon_write("+++", 3); |
457 | xmon_expect("OK", 3); | 420 | xmon_expect("OK", 3); |
458 | } | 421 | } |
459 | } | 422 | } |
460 | } | 423 | } |
461 | 424 | ||
462 | void *xmon_stdin; | 425 | void xmon_enter(void) |
463 | void *xmon_stdout; | ||
464 | void *xmon_stderr; | ||
465 | |||
466 | int xmon_putc(int c, void *f) | ||
467 | { | ||
468 | char ch = c; | ||
469 | |||
470 | if (c == '\n') | ||
471 | xmon_putc('\r', f); | ||
472 | return xmon_write(f, &ch, 1) == 1? c: -1; | ||
473 | } | ||
474 | |||
475 | int xmon_putchar(int c) | ||
476 | { | ||
477 | return xmon_putc(c, xmon_stdout); | ||
478 | } | ||
479 | |||
480 | int xmon_fputs(char *str, void *f) | ||
481 | { | ||
482 | int n = strlen(str); | ||
483 | |||
484 | return xmon_write(f, str, n) == n? 0: -1; | ||
485 | } | ||
486 | |||
487 | int | ||
488 | xmon_readchar(void) | ||
489 | { | ||
490 | char ch; | ||
491 | |||
492 | for (;;) { | ||
493 | switch (xmon_read(xmon_stdin, &ch, 1)) { | ||
494 | case 1: | ||
495 | return ch; | ||
496 | case -1: | ||
497 | xmon_printf("read(stdin) returned -1\r\n", 0, 0); | ||
498 | return -1; | ||
499 | } | ||
500 | } | ||
501 | } | ||
502 | |||
503 | static char line[256]; | ||
504 | static char *lineptr; | ||
505 | static int lineleft; | ||
506 | |||
507 | int xmon_expect(const char *str, unsigned int timeout) | ||
508 | { | ||
509 | int c; | ||
510 | unsigned int t0; | ||
511 | |||
512 | timeout *= TB_SPEED; | ||
513 | t0 = readtb(); | ||
514 | do { | ||
515 | lineptr = line; | ||
516 | for (;;) { | ||
517 | c = xmon_read_poll(); | ||
518 | if (c == -1) { | ||
519 | if (readtb() - t0 > timeout) | ||
520 | return 0; | ||
521 | continue; | ||
522 | } | ||
523 | if (c == '\n') | ||
524 | break; | ||
525 | if (c != '\r' && lineptr < &line[sizeof(line) - 1]) | ||
526 | *lineptr++ = c; | ||
527 | } | ||
528 | *lineptr = 0; | ||
529 | } while (strstr(line, str) == NULL); | ||
530 | return 1; | ||
531 | } | ||
532 | |||
533 | int | ||
534 | xmon_getchar(void) | ||
535 | { | ||
536 | int c; | ||
537 | |||
538 | if (lineleft == 0) { | ||
539 | lineptr = line; | ||
540 | for (;;) { | ||
541 | c = xmon_readchar(); | ||
542 | if (c == -1 || c == 4) | ||
543 | break; | ||
544 | if (c == '\r' || c == '\n') { | ||
545 | *lineptr++ = '\n'; | ||
546 | xmon_putchar('\n'); | ||
547 | break; | ||
548 | } | ||
549 | switch (c) { | ||
550 | case 0177: | ||
551 | case '\b': | ||
552 | if (lineptr > line) { | ||
553 | xmon_putchar('\b'); | ||
554 | xmon_putchar(' '); | ||
555 | xmon_putchar('\b'); | ||
556 | --lineptr; | ||
557 | } | ||
558 | break; | ||
559 | case 'U' & 0x1F: | ||
560 | while (lineptr > line) { | ||
561 | xmon_putchar('\b'); | ||
562 | xmon_putchar(' '); | ||
563 | xmon_putchar('\b'); | ||
564 | --lineptr; | ||
565 | } | ||
566 | break; | ||
567 | default: | ||
568 | if (lineptr >= &line[sizeof(line) - 1]) | ||
569 | xmon_putchar('\a'); | ||
570 | else { | ||
571 | xmon_putchar(c); | ||
572 | *lineptr++ = c; | ||
573 | } | ||
574 | } | ||
575 | } | ||
576 | lineleft = lineptr - line; | ||
577 | lineptr = line; | ||
578 | } | ||
579 | if (lineleft == 0) | ||
580 | return -1; | ||
581 | --lineleft; | ||
582 | return *lineptr++; | ||
583 | } | ||
584 | |||
585 | char * | ||
586 | xmon_fgets(char *str, int nb, void *f) | ||
587 | { | ||
588 | char *p; | ||
589 | int c; | ||
590 | |||
591 | for (p = str; p < str + nb - 1; ) { | ||
592 | c = xmon_getchar(); | ||
593 | if (c == -1) { | ||
594 | if (p == str) | ||
595 | return NULL; | ||
596 | break; | ||
597 | } | ||
598 | *p++ = c; | ||
599 | if (c == '\n') | ||
600 | break; | ||
601 | } | ||
602 | *p = 0; | ||
603 | return str; | ||
604 | } | ||
605 | |||
606 | void | ||
607 | xmon_enter(void) | ||
608 | { | 426 | { |
609 | #ifdef CONFIG_ADB_PMU | 427 | #ifdef CONFIG_ADB_PMU |
610 | if (_machine == _MACH_Pmac) { | 428 | if (_machine == _MACH_Pmac) { |
@@ -613,8 +431,7 @@ xmon_enter(void) | |||
613 | #endif | 431 | #endif |
614 | } | 432 | } |
615 | 433 | ||
616 | void | 434 | void xmon_leave(void) |
617 | xmon_leave(void) | ||
618 | { | 435 | { |
619 | #ifdef CONFIG_ADB_PMU | 436 | #ifdef CONFIG_ADB_PMU |
620 | if (_machine == _MACH_Pmac) { | 437 | if (_machine == _MACH_Pmac) { |
diff --git a/arch/powerpc/xmon/start_64.c b/arch/powerpc/xmon/start_64.c index e50c158191e1..712552c4f242 100644 --- a/arch/powerpc/xmon/start_64.c +++ b/arch/powerpc/xmon/start_64.c | |||
@@ -6,182 +6,29 @@ | |||
6 | * as published by the Free Software Foundation; either version | 6 | * as published by the Free Software Foundation; either version |
7 | * 2 of the License, or (at your option) any later version. | 7 | * 2 of the License, or (at your option) any later version. |
8 | */ | 8 | */ |
9 | #include <linux/config.h> | ||
10 | #include <linux/string.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/errno.h> | ||
13 | #include <linux/sysrq.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <asm/machdep.h> | 9 | #include <asm/machdep.h> |
16 | #include <asm/io.h> | ||
17 | #include <asm/page.h> | ||
18 | #include <asm/prom.h> | ||
19 | #include <asm/processor.h> | ||
20 | #include <asm/udbg.h> | 10 | #include <asm/udbg.h> |
21 | #include <asm/system.h> | ||
22 | #include "nonstdio.h" | 11 | #include "nonstdio.h" |
23 | 12 | ||
24 | #ifdef CONFIG_MAGIC_SYSRQ | 13 | void xmon_map_scc(void) |
25 | |||
26 | static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs, | ||
27 | struct tty_struct *tty) | ||
28 | { | ||
29 | /* ensure xmon is enabled */ | ||
30 | xmon_init(1); | ||
31 | debugger(pt_regs); | ||
32 | } | ||
33 | |||
34 | static struct sysrq_key_op sysrq_xmon_op = | ||
35 | { | 14 | { |
36 | .handler = sysrq_handle_xmon, | ||
37 | .help_msg = "Xmon", | ||
38 | .action_msg = "Entering xmon", | ||
39 | }; | ||
40 | |||
41 | static int __init setup_xmon_sysrq(void) | ||
42 | { | ||
43 | register_sysrq_key('x', &sysrq_xmon_op); | ||
44 | return 0; | ||
45 | } | 15 | } |
46 | __initcall(setup_xmon_sysrq); | ||
47 | #endif /* CONFIG_MAGIC_SYSRQ */ | ||
48 | 16 | ||
49 | int | 17 | int xmon_write(void *ptr, int nb) |
50 | xmon_write(void *handle, void *ptr, int nb) | ||
51 | { | 18 | { |
52 | return udbg_write(ptr, nb); | 19 | return udbg_write(ptr, nb); |
53 | } | 20 | } |
54 | 21 | ||
55 | int | 22 | int xmon_readchar(void) |
56 | xmon_read(void *handle, void *ptr, int nb) | ||
57 | { | 23 | { |
58 | return udbg_read(ptr, nb); | 24 | if (udbg_getc) |
25 | return udbg_getc(); | ||
26 | return -1; | ||
59 | } | 27 | } |
60 | 28 | ||
61 | int | 29 | int xmon_read_poll(void) |
62 | xmon_read_poll(void) | ||
63 | { | 30 | { |
64 | if (udbg_getc_poll) | 31 | if (udbg_getc_poll) |
65 | return udbg_getc_poll(); | 32 | return udbg_getc_poll(); |
66 | return -1; | 33 | return -1; |
67 | } | 34 | } |
68 | |||
69 | FILE *xmon_stdin; | ||
70 | FILE *xmon_stdout; | ||
71 | |||
72 | int | ||
73 | xmon_putc(int c, void *f) | ||
74 | { | ||
75 | char ch = c; | ||
76 | |||
77 | if (c == '\n') | ||
78 | xmon_putc('\r', f); | ||
79 | return xmon_write(f, &ch, 1) == 1? c: -1; | ||
80 | } | ||
81 | |||
82 | int | ||
83 | xmon_putchar(int c) | ||
84 | { | ||
85 | return xmon_putc(c, xmon_stdout); | ||
86 | } | ||
87 | |||
88 | int | ||
89 | xmon_fputs(char *str, void *f) | ||
90 | { | ||
91 | int n = strlen(str); | ||
92 | |||
93 | return xmon_write(f, str, n) == n? 0: -1; | ||
94 | } | ||
95 | |||
96 | int | ||
97 | xmon_readchar(void) | ||
98 | { | ||
99 | char ch; | ||
100 | |||
101 | for (;;) { | ||
102 | switch (xmon_read(xmon_stdin, &ch, 1)) { | ||
103 | case 1: | ||
104 | return ch; | ||
105 | case -1: | ||
106 | xmon_printf("read(stdin) returned -1\r\n", 0, 0); | ||
107 | return -1; | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | |||
112 | static char line[256]; | ||
113 | static char *lineptr; | ||
114 | static int lineleft; | ||
115 | |||
116 | int | ||
117 | xmon_getchar(void) | ||
118 | { | ||
119 | int c; | ||
120 | |||
121 | if (lineleft == 0) { | ||
122 | lineptr = line; | ||
123 | for (;;) { | ||
124 | c = xmon_readchar(); | ||
125 | if (c == -1 || c == 4) | ||
126 | break; | ||
127 | if (c == '\r' || c == '\n') { | ||
128 | *lineptr++ = '\n'; | ||
129 | xmon_putchar('\n'); | ||
130 | break; | ||
131 | } | ||
132 | switch (c) { | ||
133 | case 0177: | ||
134 | case '\b': | ||
135 | if (lineptr > line) { | ||
136 | xmon_putchar('\b'); | ||
137 | xmon_putchar(' '); | ||
138 | xmon_putchar('\b'); | ||
139 | --lineptr; | ||
140 | } | ||
141 | break; | ||
142 | case 'U' & 0x1F: | ||
143 | while (lineptr > line) { | ||
144 | xmon_putchar('\b'); | ||
145 | xmon_putchar(' '); | ||
146 | xmon_putchar('\b'); | ||
147 | --lineptr; | ||
148 | } | ||
149 | break; | ||
150 | default: | ||
151 | if (lineptr >= &line[sizeof(line) - 1]) | ||
152 | xmon_putchar('\a'); | ||
153 | else { | ||
154 | xmon_putchar(c); | ||
155 | *lineptr++ = c; | ||
156 | } | ||
157 | } | ||
158 | } | ||
159 | lineleft = lineptr - line; | ||
160 | lineptr = line; | ||
161 | } | ||
162 | if (lineleft == 0) | ||
163 | return -1; | ||
164 | --lineleft; | ||
165 | return *lineptr++; | ||
166 | } | ||
167 | |||
168 | char * | ||
169 | xmon_fgets(char *str, int nb, void *f) | ||
170 | { | ||
171 | char *p; | ||
172 | int c; | ||
173 | |||
174 | for (p = str; p < str + nb - 1; ) { | ||
175 | c = xmon_getchar(); | ||
176 | if (c == -1) { | ||
177 | if (p == str) | ||
178 | return NULL; | ||
179 | break; | ||
180 | } | ||
181 | *p++ = c; | ||
182 | if (c == '\n') | ||
183 | break; | ||
184 | } | ||
185 | *p = 0; | ||
186 | return str; | ||
187 | } | ||
diff --git a/arch/powerpc/xmon/start_8xx.c b/arch/powerpc/xmon/start_8xx.c index a48bd594cf61..4c17b0486ad5 100644 --- a/arch/powerpc/xmon/start_8xx.c +++ b/arch/powerpc/xmon/start_8xx.c | |||
@@ -15,273 +15,30 @@ | |||
15 | #include <asm/8xx_immap.h> | 15 | #include <asm/8xx_immap.h> |
16 | #include <asm/mpc8xx.h> | 16 | #include <asm/mpc8xx.h> |
17 | #include <asm/commproc.h> | 17 | #include <asm/commproc.h> |
18 | #include "nonstdio.h" | ||
18 | 19 | ||
19 | extern void xmon_printf(const char *fmt, ...); | ||
20 | extern int xmon_8xx_write(char *str, int nb); | 20 | extern int xmon_8xx_write(char *str, int nb); |
21 | extern int xmon_8xx_read_poll(void); | 21 | extern int xmon_8xx_read_poll(void); |
22 | extern int xmon_8xx_read_char(void); | 22 | extern int xmon_8xx_read_char(void); |
23 | void prom_drawhex(uint); | ||
24 | void prom_drawstring(const char *str); | ||
25 | 23 | ||
26 | static int use_screen = 1; /* default */ | 24 | void xmon_map_scc(void) |
27 | |||
28 | #define TB_SPEED 25000000 | ||
29 | |||
30 | static inline unsigned int readtb(void) | ||
31 | { | ||
32 | unsigned int ret; | ||
33 | |||
34 | asm volatile("mftb %0" : "=r" (ret) :); | ||
35 | return ret; | ||
36 | } | ||
37 | |||
38 | void buf_access(void) | ||
39 | { | ||
40 | } | ||
41 | |||
42 | void | ||
43 | xmon_map_scc(void) | ||
44 | { | 25 | { |
45 | |||
46 | cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm); | 26 | cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm); |
47 | use_screen = 0; | ||
48 | |||
49 | prom_drawstring("xmon uses serial port\n"); | ||
50 | } | 27 | } |
51 | 28 | ||
52 | static int scc_initialized = 0; | ||
53 | |||
54 | void xmon_init_scc(void); | 29 | void xmon_init_scc(void); |
55 | 30 | ||
56 | int | 31 | int xmon_write(void *ptr, int nb) |
57 | xmon_write(void *handle, void *ptr, int nb) | ||
58 | { | 32 | { |
59 | char *p = ptr; | ||
60 | int i, c, ct; | ||
61 | |||
62 | if (!scc_initialized) | ||
63 | xmon_init_scc(); | ||
64 | |||
65 | return(xmon_8xx_write(ptr, nb)); | 33 | return(xmon_8xx_write(ptr, nb)); |
66 | } | 34 | } |
67 | 35 | ||
68 | int xmon_wants_key; | 36 | int xmon_readchar(void) |
69 | |||
70 | int | ||
71 | xmon_read(void *handle, void *ptr, int nb) | ||
72 | { | 37 | { |
73 | char *p = ptr; | 38 | return xmon_8xx_read_char(); |
74 | int i; | ||
75 | |||
76 | if (!scc_initialized) | ||
77 | xmon_init_scc(); | ||
78 | |||
79 | for (i = 0; i < nb; ++i) { | ||
80 | *p++ = xmon_8xx_read_char(); | ||
81 | } | ||
82 | return i; | ||
83 | } | 39 | } |
84 | 40 | ||
85 | int | 41 | int xmon_read_poll(void) |
86 | xmon_read_poll(void) | ||
87 | { | 42 | { |
88 | return(xmon_8xx_read_poll()); | 43 | return(xmon_8xx_read_poll()); |
89 | } | 44 | } |
90 | |||
91 | void | ||
92 | xmon_init_scc() | ||
93 | { | ||
94 | scc_initialized = 1; | ||
95 | } | ||
96 | |||
97 | #if 0 | ||
98 | extern int (*prom_entry)(void *); | ||
99 | |||
100 | int | ||
101 | xmon_exit(void) | ||
102 | { | ||
103 | struct prom_args { | ||
104 | char *service; | ||
105 | } args; | ||
106 | |||
107 | for (;;) { | ||
108 | args.service = "exit"; | ||
109 | (*prom_entry)(&args); | ||
110 | } | ||
111 | } | ||
112 | #endif | ||
113 | |||
114 | void *xmon_stdin; | ||
115 | void *xmon_stdout; | ||
116 | void *xmon_stderr; | ||
117 | |||
118 | void | ||
119 | xmon_init(void) | ||
120 | { | ||
121 | } | ||
122 | |||
123 | int | ||
124 | xmon_putc(int c, void *f) | ||
125 | { | ||
126 | char ch = c; | ||
127 | |||
128 | if (c == '\n') | ||
129 | xmon_putc('\r', f); | ||
130 | return xmon_write(f, &ch, 1) == 1? c: -1; | ||
131 | } | ||
132 | |||
133 | int | ||
134 | xmon_putchar(int c) | ||
135 | { | ||
136 | return xmon_putc(c, xmon_stdout); | ||
137 | } | ||
138 | |||
139 | int | ||
140 | xmon_fputs(char *str, void *f) | ||
141 | { | ||
142 | int n = strlen(str); | ||
143 | |||
144 | return xmon_write(f, str, n) == n? 0: -1; | ||
145 | } | ||
146 | |||
147 | int | ||
148 | xmon_readchar(void) | ||
149 | { | ||
150 | char ch; | ||
151 | |||
152 | for (;;) { | ||
153 | switch (xmon_read(xmon_stdin, &ch, 1)) { | ||
154 | case 1: | ||
155 | return ch; | ||
156 | case -1: | ||
157 | xmon_printf("read(stdin) returned -1\r\n", 0, 0); | ||
158 | return -1; | ||
159 | } | ||
160 | } | ||
161 | } | ||
162 | |||
163 | static char line[256]; | ||
164 | static char *lineptr; | ||
165 | static int lineleft; | ||
166 | |||
167 | #if 0 | ||
168 | int xmon_expect(const char *str, unsigned int timeout) | ||
169 | { | ||
170 | int c; | ||
171 | unsigned int t0; | ||
172 | |||
173 | timeout *= TB_SPEED; | ||
174 | t0 = readtb(); | ||
175 | do { | ||
176 | lineptr = line; | ||
177 | for (;;) { | ||
178 | c = xmon_read_poll(); | ||
179 | if (c == -1) { | ||
180 | if (readtb() - t0 > timeout) | ||
181 | return 0; | ||
182 | continue; | ||
183 | } | ||
184 | if (c == '\n') | ||
185 | break; | ||
186 | if (c != '\r' && lineptr < &line[sizeof(line) - 1]) | ||
187 | *lineptr++ = c; | ||
188 | } | ||
189 | *lineptr = 0; | ||
190 | } while (strstr(line, str) == NULL); | ||
191 | return 1; | ||
192 | } | ||
193 | #endif | ||
194 | |||
195 | int | ||
196 | xmon_getchar(void) | ||
197 | { | ||
198 | int c; | ||
199 | |||
200 | if (lineleft == 0) { | ||
201 | lineptr = line; | ||
202 | for (;;) { | ||
203 | c = xmon_readchar(); | ||
204 | if (c == -1 || c == 4) | ||
205 | break; | ||
206 | if (c == '\r' || c == '\n') { | ||
207 | *lineptr++ = '\n'; | ||
208 | xmon_putchar('\n'); | ||
209 | break; | ||
210 | } | ||
211 | switch (c) { | ||
212 | case 0177: | ||
213 | case '\b': | ||
214 | if (lineptr > line) { | ||
215 | xmon_putchar('\b'); | ||
216 | xmon_putchar(' '); | ||
217 | xmon_putchar('\b'); | ||
218 | --lineptr; | ||
219 | } | ||
220 | break; | ||
221 | case 'U' & 0x1F: | ||
222 | while (lineptr > line) { | ||
223 | xmon_putchar('\b'); | ||
224 | xmon_putchar(' '); | ||
225 | xmon_putchar('\b'); | ||
226 | --lineptr; | ||
227 | } | ||
228 | break; | ||
229 | default: | ||
230 | if (lineptr >= &line[sizeof(line) - 1]) | ||
231 | xmon_putchar('\a'); | ||
232 | else { | ||
233 | xmon_putchar(c); | ||
234 | *lineptr++ = c; | ||
235 | } | ||
236 | } | ||
237 | } | ||
238 | lineleft = lineptr - line; | ||
239 | lineptr = line; | ||
240 | } | ||
241 | if (lineleft == 0) | ||
242 | return -1; | ||
243 | --lineleft; | ||
244 | return *lineptr++; | ||
245 | } | ||
246 | |||
247 | char * | ||
248 | xmon_fgets(char *str, int nb, void *f) | ||
249 | { | ||
250 | char *p; | ||
251 | int c; | ||
252 | |||
253 | for (p = str; p < str + nb - 1; ) { | ||
254 | c = xmon_getchar(); | ||
255 | if (c == -1) { | ||
256 | if (p == str) | ||
257 | return 0; | ||
258 | break; | ||
259 | } | ||
260 | *p++ = c; | ||
261 | if (c == '\n') | ||
262 | break; | ||
263 | } | ||
264 | *p = 0; | ||
265 | return str; | ||
266 | } | ||
267 | |||
268 | void | ||
269 | prom_drawhex(uint val) | ||
270 | { | ||
271 | unsigned char buf[10]; | ||
272 | |||
273 | int i; | ||
274 | for (i = 7; i >= 0; i--) | ||
275 | { | ||
276 | buf[i] = "0123456789abcdef"[val & 0x0f]; | ||
277 | val >>= 4; | ||
278 | } | ||
279 | buf[8] = '\0'; | ||
280 | xmon_fputs(buf, xmon_stdout); | ||
281 | } | ||
282 | |||
283 | void | ||
284 | prom_drawstring(const char *str) | ||
285 | { | ||
286 | xmon_fputs(str, xmon_stdout); | ||
287 | } | ||
diff --git a/arch/powerpc/xmon/subr_prf.c b/arch/powerpc/xmon/subr_prf.c deleted file mode 100644 index b48738c6dd33..000000000000 --- a/arch/powerpc/xmon/subr_prf.c +++ /dev/null | |||
@@ -1,54 +0,0 @@ | |||
1 | /* | ||
2 | * Written by Cort Dougan to replace the version originally used | ||
3 | * by Paul Mackerras, which came from NetBSD and thus had copyright | ||
4 | * conflicts with Linux. | ||
5 | * | ||
6 | * This file makes liberal use of the standard linux utility | ||
7 | * routines to reduce the size of the binary. We assume we can | ||
8 | * trust some parts of Linux inside the debugger. | ||
9 | * -- Cort (cort@cs.nmt.edu) | ||
10 | * | ||
11 | * Copyright (C) 1999 Cort Dougan. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version | ||
16 | * 2 of the License, or (at your option) any later version. | ||
17 | */ | ||
18 | |||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <stdarg.h> | ||
23 | #include "nonstdio.h" | ||
24 | |||
25 | extern int xmon_write(void *, void *, int); | ||
26 | |||
27 | void xmon_vfprintf(void *f, const char *fmt, va_list ap) | ||
28 | { | ||
29 | static char xmon_buf[2048]; | ||
30 | int n; | ||
31 | |||
32 | n = vsprintf(xmon_buf, fmt, ap); | ||
33 | xmon_write(f, xmon_buf, n); | ||
34 | } | ||
35 | |||
36 | void xmon_printf(const char *fmt, ...) | ||
37 | { | ||
38 | va_list ap; | ||
39 | |||
40 | va_start(ap, fmt); | ||
41 | xmon_vfprintf(stdout, fmt, ap); | ||
42 | va_end(ap); | ||
43 | } | ||
44 | EXPORT_SYMBOL(xmon_printf); | ||
45 | |||
46 | void xmon_fprintf(void *f, const char *fmt, ...) | ||
47 | { | ||
48 | va_list ap; | ||
49 | |||
50 | va_start(ap, fmt); | ||
51 | xmon_vfprintf(f, fmt, ap); | ||
52 | va_end(ap); | ||
53 | } | ||
54 | |||
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 1124f1146202..cfcb2a56d662 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Routines providing a simple monitor for use on the PowerMac. | 2 | * Routines providing a simple monitor for use on the PowerMac. |
3 | * | 3 | * |
4 | * Copyright (C) 1996 Paul Mackerras. | 4 | * Copyright (C) 1996-2005 Paul Mackerras. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License | 7 | * modify it under the terms of the GNU General Public License |
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/kallsyms.h> | 18 | #include <linux/kallsyms.h> |
19 | #include <linux/cpumask.h> | 19 | #include <linux/cpumask.h> |
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/sysrq.h> | ||
21 | 22 | ||
22 | #include <asm/ptrace.h> | 23 | #include <asm/ptrace.h> |
23 | #include <asm/string.h> | 24 | #include <asm/string.h> |
@@ -144,15 +145,10 @@ static void xmon_print_symbol(unsigned long address, const char *mid, | |||
144 | static const char *getvecname(unsigned long vec); | 145 | static const char *getvecname(unsigned long vec); |
145 | 146 | ||
146 | extern int print_insn_powerpc(unsigned long, unsigned long, int); | 147 | extern int print_insn_powerpc(unsigned long, unsigned long, int); |
147 | extern void printf(const char *fmt, ...); | ||
148 | extern void xmon_vfprintf(void *f, const char *fmt, va_list ap); | ||
149 | extern int xmon_putc(int c, void *f); | ||
150 | extern int putchar(int ch); | ||
151 | 148 | ||
152 | extern void xmon_enter(void); | 149 | extern void xmon_enter(void); |
153 | extern void xmon_leave(void); | 150 | extern void xmon_leave(void); |
154 | 151 | ||
155 | extern int xmon_read_poll(void); | ||
156 | extern long setjmp(long *); | 152 | extern long setjmp(long *); |
157 | extern void longjmp(long *, long); | 153 | extern void longjmp(long *, long); |
158 | extern void xmon_save_regs(struct pt_regs *); | 154 | extern void xmon_save_regs(struct pt_regs *); |
@@ -748,7 +744,6 @@ cmds(struct pt_regs *excp) | |||
748 | printf("%x:", smp_processor_id()); | 744 | printf("%x:", smp_processor_id()); |
749 | #endif /* CONFIG_SMP */ | 745 | #endif /* CONFIG_SMP */ |
750 | printf("mon> "); | 746 | printf("mon> "); |
751 | fflush(stdout); | ||
752 | flush_input(); | 747 | flush_input(); |
753 | termch = 0; | 748 | termch = 0; |
754 | cmd = skipbl(); | 749 | cmd = skipbl(); |
@@ -1797,7 +1792,7 @@ memex(void) | |||
1797 | for(;;){ | 1792 | for(;;){ |
1798 | if (!mnoread) | 1793 | if (!mnoread) |
1799 | n = mread(adrs, val, size); | 1794 | n = mread(adrs, val, size); |
1800 | printf("%.16x%c", adrs, brev? 'r': ' '); | 1795 | printf(REG"%c", adrs, brev? 'r': ' '); |
1801 | if (!mnoread) { | 1796 | if (!mnoread) { |
1802 | if (brev) | 1797 | if (brev) |
1803 | byterev(val, size); | 1798 | byterev(val, size); |
@@ -1976,17 +1971,18 @@ prdump(unsigned long adrs, long ndump) | |||
1976 | nr = mread(adrs, temp, r); | 1971 | nr = mread(adrs, temp, r); |
1977 | adrs += nr; | 1972 | adrs += nr; |
1978 | for (m = 0; m < r; ++m) { | 1973 | for (m = 0; m < r; ++m) { |
1979 | if ((m & 7) == 0 && m > 0) | 1974 | if ((m & (sizeof(long) - 1)) == 0 && m > 0) |
1980 | putchar(' '); | 1975 | putchar(' '); |
1981 | if (m < nr) | 1976 | if (m < nr) |
1982 | printf("%.2x", temp[m]); | 1977 | printf("%.2x", temp[m]); |
1983 | else | 1978 | else |
1984 | printf("%s", fault_chars[fault_type]); | 1979 | printf("%s", fault_chars[fault_type]); |
1985 | } | 1980 | } |
1986 | if (m <= 8) | 1981 | for (; m < 16; ++m) { |
1987 | printf(" "); | 1982 | if ((m & (sizeof(long) - 1)) == 0) |
1988 | for (; m < 16; ++m) | 1983 | putchar(' '); |
1989 | printf(" "); | 1984 | printf(" "); |
1985 | } | ||
1990 | printf(" |"); | 1986 | printf(" |"); |
1991 | for (m = 0; m < r; ++m) { | 1987 | for (m = 0; m < r; ++m) { |
1992 | if (m < nr) { | 1988 | if (m < nr) { |
@@ -2151,7 +2147,6 @@ memzcan(void) | |||
2151 | ok = mread(a, &v, 1); | 2147 | ok = mread(a, &v, 1); |
2152 | if (ok && !ook) { | 2148 | if (ok && !ook) { |
2153 | printf("%.8x .. ", a); | 2149 | printf("%.8x .. ", a); |
2154 | fflush(stdout); | ||
2155 | } else if (!ok && ook) | 2150 | } else if (!ok && ook) |
2156 | printf("%.8x\n", a - mskip); | 2151 | printf("%.8x\n", a - mskip); |
2157 | ook = ok; | 2152 | ook = ok; |
@@ -2372,7 +2367,7 @@ int | |||
2372 | inchar(void) | 2367 | inchar(void) |
2373 | { | 2368 | { |
2374 | if (lineptr == NULL || *lineptr == 0) { | 2369 | if (lineptr == NULL || *lineptr == 0) { |
2375 | if (fgets(line, sizeof(line), stdin) == NULL) { | 2370 | if (xmon_gets(line, sizeof(line)) == NULL) { |
2376 | lineptr = NULL; | 2371 | lineptr = NULL; |
2377 | return EOF; | 2372 | return EOF; |
2378 | } | 2373 | } |
@@ -2526,4 +2521,29 @@ void xmon_init(int enable) | |||
2526 | __debugger_dabr_match = NULL; | 2521 | __debugger_dabr_match = NULL; |
2527 | __debugger_fault_handler = NULL; | 2522 | __debugger_fault_handler = NULL; |
2528 | } | 2523 | } |
2524 | xmon_map_scc(); | ||
2525 | } | ||
2526 | |||
2527 | #ifdef CONFIG_MAGIC_SYSRQ | ||
2528 | static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs, | ||
2529 | struct tty_struct *tty) | ||
2530 | { | ||
2531 | /* ensure xmon is enabled */ | ||
2532 | xmon_init(1); | ||
2533 | debugger(pt_regs); | ||
2534 | } | ||
2535 | |||
2536 | static struct sysrq_key_op sysrq_xmon_op = | ||
2537 | { | ||
2538 | .handler = sysrq_handle_xmon, | ||
2539 | .help_msg = "Xmon", | ||
2540 | .action_msg = "Entering xmon", | ||
2541 | }; | ||
2542 | |||
2543 | static int __init setup_xmon_sysrq(void) | ||
2544 | { | ||
2545 | register_sysrq_key('x', &sysrq_xmon_op); | ||
2546 | return 0; | ||
2529 | } | 2547 | } |
2548 | __initcall(setup_xmon_sysrq); | ||
2549 | #endif /* CONFIG_MAGIC_SYSRQ */ | ||
diff --git a/arch/ppc/boot/include/of1275.h b/arch/ppc/boot/include/of1275.h index 69173df76db0..4ed88acfa73a 100644 --- a/arch/ppc/boot/include/of1275.h +++ b/arch/ppc/boot/include/of1275.h | |||
@@ -19,6 +19,9 @@ extern prom_entry of_prom_entry; | |||
19 | 19 | ||
20 | /* function declarations */ | 20 | /* function declarations */ |
21 | 21 | ||
22 | int call_prom(const char *service, int nargs, int nret, ...); | ||
23 | int call_prom_ret(const char *service, int nargs, int nret, | ||
24 | unsigned int *rets, ...); | ||
22 | void * claim(unsigned int virt, unsigned int size, unsigned int align); | 25 | void * claim(unsigned int virt, unsigned int size, unsigned int align); |
23 | int map(unsigned int phys, unsigned int virt, unsigned int size); | 26 | int map(unsigned int phys, unsigned int virt, unsigned int size); |
24 | void enter(void); | 27 | void enter(void); |
diff --git a/arch/ppc/boot/of1275/Makefile b/arch/ppc/boot/of1275/Makefile index 02e6f235d7cb..0b979c004972 100644 --- a/arch/ppc/boot/of1275/Makefile +++ b/arch/ppc/boot/of1275/Makefile | |||
@@ -3,4 +3,4 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | lib-y := claim.o enter.o exit.o finddevice.o getprop.o ofinit.o \ | 5 | lib-y := claim.o enter.o exit.o finddevice.o getprop.o ofinit.o \ |
6 | ofstdio.o read.o release.o write.o map.o | 6 | ofstdio.o read.o release.o write.o map.o call_prom.o |
diff --git a/arch/ppc/boot/of1275/call_prom.c b/arch/ppc/boot/of1275/call_prom.c new file mode 100644 index 000000000000..9479a3a2b8c7 --- /dev/null +++ b/arch/ppc/boot/of1275/call_prom.c | |||
@@ -0,0 +1,74 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1996-2005 Paul Mackerras. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | */ | ||
9 | |||
10 | #include "of1275.h" | ||
11 | #include <stdarg.h> | ||
12 | |||
13 | int call_prom(const char *service, int nargs, int nret, ...) | ||
14 | { | ||
15 | int i; | ||
16 | struct prom_args { | ||
17 | const char *service; | ||
18 | int nargs; | ||
19 | int nret; | ||
20 | unsigned int args[12]; | ||
21 | } args; | ||
22 | va_list list; | ||
23 | |||
24 | args.service = service; | ||
25 | args.nargs = nargs; | ||
26 | args.nret = nret; | ||
27 | |||
28 | va_start(list, nret); | ||
29 | for (i = 0; i < nargs; i++) | ||
30 | args.args[i] = va_arg(list, unsigned int); | ||
31 | va_end(list); | ||
32 | |||
33 | for (i = 0; i < nret; i++) | ||
34 | args.args[nargs+i] = 0; | ||
35 | |||
36 | if (of_prom_entry(&args) < 0) | ||
37 | return -1; | ||
38 | |||
39 | return (nret > 0)? args.args[nargs]: 0; | ||
40 | } | ||
41 | |||
42 | int call_prom_ret(const char *service, int nargs, int nret, | ||
43 | unsigned int *rets, ...) | ||
44 | { | ||
45 | int i; | ||
46 | struct prom_args { | ||
47 | const char *service; | ||
48 | int nargs; | ||
49 | int nret; | ||
50 | unsigned int args[12]; | ||
51 | } args; | ||
52 | va_list list; | ||
53 | |||
54 | args.service = service; | ||
55 | args.nargs = nargs; | ||
56 | args.nret = nret; | ||
57 | |||
58 | va_start(list, rets); | ||
59 | for (i = 0; i < nargs; i++) | ||
60 | args.args[i] = va_arg(list, unsigned int); | ||
61 | va_end(list); | ||
62 | |||
63 | for (i = 0; i < nret; i++) | ||
64 | args.args[nargs+i] = 0; | ||
65 | |||
66 | if (of_prom_entry(&args) < 0) | ||
67 | return -1; | ||
68 | |||
69 | if (rets != (void *) 0) | ||
70 | for (i = 1; i < nret; ++i) | ||
71 | rets[i-1] = args.args[nargs+i]; | ||
72 | |||
73 | return (nret > 0)? args.args[nargs]: 0; | ||
74 | } | ||
diff --git a/arch/ppc/boot/of1275/claim.c b/arch/ppc/boot/of1275/claim.c index 13169a5c4339..1ed3aeeff8ae 100644 --- a/arch/ppc/boot/of1275/claim.c +++ b/arch/ppc/boot/of1275/claim.c | |||
@@ -9,27 +9,84 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include "of1275.h" | 11 | #include "of1275.h" |
12 | #include "nonstdio.h" | ||
12 | 13 | ||
13 | void * | 14 | /* |
14 | claim(unsigned int virt, unsigned int size, unsigned int align) | 15 | * Older OF's require that when claiming a specific range of addresses, |
16 | * we claim the physical space in the /memory node and the virtual | ||
17 | * space in the chosen mmu node, and then do a map operation to | ||
18 | * map virtual to physical. | ||
19 | */ | ||
20 | static int need_map = -1; | ||
21 | static ihandle chosen_mmu; | ||
22 | static phandle memory; | ||
23 | |||
24 | /* returns true if s2 is a prefix of s1 */ | ||
25 | static int string_match(const char *s1, const char *s2) | ||
26 | { | ||
27 | for (; *s2; ++s2) | ||
28 | if (*s1++ != *s2) | ||
29 | return 0; | ||
30 | return 1; | ||
31 | } | ||
32 | |||
33 | static int check_of_version(void) | ||
34 | { | ||
35 | phandle oprom, chosen; | ||
36 | char version[64]; | ||
37 | |||
38 | oprom = finddevice("/openprom"); | ||
39 | if (oprom == OF_INVALID_HANDLE) | ||
40 | return 0; | ||
41 | if (getprop(oprom, "model", version, sizeof(version)) <= 0) | ||
42 | return 0; | ||
43 | version[sizeof(version)-1] = 0; | ||
44 | printf("OF version = '%s'\n", version); | ||
45 | if (!string_match(version, "Open Firmware, 1.") | ||
46 | && !string_match(version, "FirmWorks,3.")) | ||
47 | return 0; | ||
48 | chosen = finddevice("/chosen"); | ||
49 | if (chosen == OF_INVALID_HANDLE) { | ||
50 | chosen = finddevice("/chosen@0"); | ||
51 | if (chosen == OF_INVALID_HANDLE) { | ||
52 | printf("no chosen\n"); | ||
53 | return 0; | ||
54 | } | ||
55 | } | ||
56 | if (getprop(chosen, "mmu", &chosen_mmu, sizeof(chosen_mmu)) <= 0) { | ||
57 | printf("no mmu\n"); | ||
58 | return 0; | ||
59 | } | ||
60 | memory = (ihandle) call_prom("open", 1, 1, "/memory"); | ||
61 | if (memory == OF_INVALID_HANDLE) { | ||
62 | memory = (ihandle) call_prom("open", 1, 1, "/memory@0"); | ||
63 | if (memory == OF_INVALID_HANDLE) { | ||
64 | printf("no memory node\n"); | ||
65 | return 0; | ||
66 | } | ||
67 | } | ||
68 | printf("old OF detected\n"); | ||
69 | return 1; | ||
70 | } | ||
71 | |||
72 | void *claim(unsigned int virt, unsigned int size, unsigned int align) | ||
15 | { | 73 | { |
16 | struct prom_args { | 74 | int ret; |
17 | char *service; | 75 | unsigned int result; |
18 | int nargs; | ||
19 | int nret; | ||
20 | unsigned int virt; | ||
21 | unsigned int size; | ||
22 | unsigned int align; | ||
23 | void *ret; | ||
24 | } args; | ||
25 | 76 | ||
26 | args.service = "claim"; | 77 | if (need_map < 0) |
27 | args.nargs = 3; | 78 | need_map = check_of_version(); |
28 | args.nret = 1; | 79 | if (align || !need_map) |
29 | args.virt = virt; | 80 | return (void *) call_prom("claim", 3, 1, virt, size, align); |
30 | args.size = size; | 81 | |
31 | args.align = align; | 82 | ret = call_prom_ret("call-method", 5, 2, &result, "claim", memory, |
32 | args.ret = (void *) 0; | 83 | align, size, virt); |
33 | (*of_prom_entry)(&args); | 84 | if (ret != 0 || result == -1) |
34 | return args.ret; | 85 | return (void *) -1; |
86 | ret = call_prom_ret("call-method", 5, 2, &result, "claim", chosen_mmu, | ||
87 | align, size, virt); | ||
88 | /* 0x12 == coherent + read/write */ | ||
89 | ret = call_prom("call-method", 6, 1, "map", chosen_mmu, | ||
90 | 0x12, size, virt, virt); | ||
91 | return virt; | ||
35 | } | 92 | } |
diff --git a/arch/ppc/boot/of1275/finddevice.c b/arch/ppc/boot/of1275/finddevice.c index 2c0f7cbb793e..0dcb1201b772 100644 --- a/arch/ppc/boot/of1275/finddevice.c +++ b/arch/ppc/boot/of1275/finddevice.c | |||
@@ -10,22 +10,7 @@ | |||
10 | 10 | ||
11 | #include "of1275.h" | 11 | #include "of1275.h" |
12 | 12 | ||
13 | phandle | 13 | phandle finddevice(const char *name) |
14 | finddevice(const char *name) | ||
15 | { | 14 | { |
16 | struct prom_args { | 15 | return (phandle) call_prom("finddevice", 1, 1, name); |
17 | char *service; | ||
18 | int nargs; | ||
19 | int nret; | ||
20 | const char *devspec; | ||
21 | phandle device; | ||
22 | } args; | ||
23 | |||
24 | args.service = "finddevice"; | ||
25 | args.nargs = 1; | ||
26 | args.nret = 1; | ||
27 | args.devspec = name; | ||
28 | args.device = OF_INVALID_HANDLE; | ||
29 | (*of_prom_entry)(&args); | ||
30 | return args.device; | ||
31 | } | 16 | } |
diff --git a/arch/ppc/boot/openfirmware/Makefile b/arch/ppc/boot/openfirmware/Makefile index 03415238fabf..83a6433459ce 100644 --- a/arch/ppc/boot/openfirmware/Makefile +++ b/arch/ppc/boot/openfirmware/Makefile | |||
@@ -80,8 +80,7 @@ $(obj)/note: $(utils)/mknote FORCE | |||
80 | $(call if_changed,mknote) | 80 | $(call if_changed,mknote) |
81 | 81 | ||
82 | 82 | ||
83 | $(obj)/coffcrt0.o: EXTRA_AFLAGS := -traditional -DXCOFF | 83 | $(obj)/coffcrt0.o: EXTRA_AFLAGS := -DXCOFF |
84 | $(obj)/crt0.o: EXTRA_AFLAGS := -traditional | ||
85 | targets += coffcrt0.o crt0.o | 84 | targets += coffcrt0.o crt0.o |
86 | $(obj)/coffcrt0.o $(obj)/crt0.o: $(common)/crt0.S FORCE | 85 | $(obj)/coffcrt0.o $(obj)/crt0.o: $(common)/crt0.S FORCE |
87 | $(call if_changed_dep,as_o_S) | 86 | $(call if_changed_dep,as_o_S) |
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 76a55a438f23..17a4da65e275 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile | |||
@@ -12,7 +12,7 @@ extra-$(CONFIG_6xx) += idle_6xx.o | |||
12 | extra-$(CONFIG_POWER4) += idle_power4.o | 12 | extra-$(CONFIG_POWER4) += idle_power4.o |
13 | extra-y += vmlinux.lds | 13 | extra-y += vmlinux.lds |
14 | 14 | ||
15 | obj-y := entry.o traps.o irq.o idle.o time.o misc.o \ | 15 | obj-y := entry.o traps.o idle.o time.o misc.o \ |
16 | process.o align.o \ | 16 | process.o align.o \ |
17 | setup.o \ | 17 | setup.o \ |
18 | ppc_htab.o | 18 | ppc_htab.o |
@@ -38,8 +38,7 @@ endif | |||
38 | # These are here while we do the architecture merge | 38 | # These are here while we do the architecture merge |
39 | 39 | ||
40 | else | 40 | else |
41 | obj-y := irq.o idle.o \ | 41 | obj-y := idle.o align.o |
42 | align.o | ||
43 | obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o | 42 | obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o |
44 | obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o | 43 | obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o |
45 | obj-$(CONFIG_MODULES) += module.o | 44 | obj-$(CONFIG_MODULES) += module.o |
diff --git a/arch/ppc/kernel/head_booke.h b/arch/ppc/kernel/head_booke.h index aeb349b47af3..f3d274c6b231 100644 --- a/arch/ppc/kernel/head_booke.h +++ b/arch/ppc/kernel/head_booke.h | |||
@@ -358,6 +358,6 @@ label: | |||
358 | NORMAL_EXCEPTION_PROLOG; \ | 358 | NORMAL_EXCEPTION_PROLOG; \ |
359 | bne load_up_fpu; /* if from user, just load it up */ \ | 359 | bne load_up_fpu; /* if from user, just load it up */ \ |
360 | addi r3,r1,STACK_FRAME_OVERHEAD; \ | 360 | addi r3,r1,STACK_FRAME_OVERHEAD; \ |
361 | EXC_XFER_EE_LITE(0x800, KernelFP) | 361 | EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception) |
362 | 362 | ||
363 | #endif /* __HEAD_BOOKE_H__ */ | 363 | #endif /* __HEAD_BOOKE_H__ */ |
diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c index 3c4e4cb61074..821a75e45602 100644 --- a/arch/ppc/kernel/idle.c +++ b/arch/ppc/kernel/idle.c | |||
@@ -63,7 +63,7 @@ void cpu_idle(void) | |||
63 | int cpu = smp_processor_id(); | 63 | int cpu = smp_processor_id(); |
64 | 64 | ||
65 | for (;;) { | 65 | for (;;) { |
66 | while (need_resched()) { | 66 | while (!need_resched()) { |
67 | if (ppc_md.idle != NULL) | 67 | if (ppc_md.idle != NULL) |
68 | ppc_md.idle(); | 68 | ppc_md.idle(); |
69 | else | 69 | else |
diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c deleted file mode 100644 index fbb2b9f8922c..000000000000 --- a/arch/ppc/kernel/irq.c +++ /dev/null | |||
@@ -1,165 +0,0 @@ | |||
1 | /* | ||
2 | * arch/ppc/kernel/irq.c | ||
3 | * | ||
4 | * Derived from arch/i386/kernel/irq.c | ||
5 | * Copyright (C) 1992 Linus Torvalds | ||
6 | * Adapted from arch/i386 by Gary Thomas | ||
7 | * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) | ||
8 | * Updated and modified by Cort Dougan <cort@fsmlabs.com> | ||
9 | * Copyright (C) 1996-2001 Cort Dougan | ||
10 | * Adapted for Power Macintosh by Paul Mackerras | ||
11 | * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) | ||
12 | * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). | ||
13 | * | ||
14 | * This file contains the code used by various IRQ handling routines: | ||
15 | * asking for different IRQ's should be done through these routines | ||
16 | * instead of just grabbing them. Thus setups with different IRQ numbers | ||
17 | * shouldn't result in any weird surprises, and installing new handlers | ||
18 | * should be easier. | ||
19 | * | ||
20 | * The MPC8xx has an interrupt mask in the SIU. If a bit is set, the | ||
21 | * interrupt is _enabled_. As expected, IRQ0 is bit 0 in the 32-bit | ||
22 | * mask register (of which only 16 are defined), hence the weird shifting | ||
23 | * and complement of the cached_irq_mask. I want to be able to stuff | ||
24 | * this right into the SIU SMASK register. | ||
25 | * Many of the prep/chrp functions are conditional compiled on CONFIG_8xx | ||
26 | * to reduce code space and undefined function references. | ||
27 | */ | ||
28 | |||
29 | #include <linux/errno.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/threads.h> | ||
32 | #include <linux/kernel_stat.h> | ||
33 | #include <linux/signal.h> | ||
34 | #include <linux/sched.h> | ||
35 | #include <linux/ptrace.h> | ||
36 | #include <linux/ioport.h> | ||
37 | #include <linux/interrupt.h> | ||
38 | #include <linux/timex.h> | ||
39 | #include <linux/config.h> | ||
40 | #include <linux/init.h> | ||
41 | #include <linux/slab.h> | ||
42 | #include <linux/pci.h> | ||
43 | #include <linux/delay.h> | ||
44 | #include <linux/irq.h> | ||
45 | #include <linux/proc_fs.h> | ||
46 | #include <linux/random.h> | ||
47 | #include <linux/seq_file.h> | ||
48 | #include <linux/cpumask.h> | ||
49 | #include <linux/profile.h> | ||
50 | #include <linux/bitops.h> | ||
51 | |||
52 | #include <asm/uaccess.h> | ||
53 | #include <asm/system.h> | ||
54 | #include <asm/io.h> | ||
55 | #include <asm/pgtable.h> | ||
56 | #include <asm/irq.h> | ||
57 | #include <asm/cache.h> | ||
58 | #include <asm/prom.h> | ||
59 | #include <asm/ptrace.h> | ||
60 | #include <asm/machdep.h> | ||
61 | |||
62 | #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) | ||
63 | |||
64 | extern atomic_t ipi_recv; | ||
65 | extern atomic_t ipi_sent; | ||
66 | |||
67 | #define MAXCOUNT 10000000 | ||
68 | |||
69 | int ppc_spurious_interrupts = 0; | ||
70 | struct irqaction *ppc_irq_action[NR_IRQS]; | ||
71 | unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; | ||
72 | unsigned long ppc_lost_interrupts[NR_MASK_WORDS]; | ||
73 | atomic_t ppc_n_lost_interrupts; | ||
74 | |||
75 | #ifdef CONFIG_TAU_INT | ||
76 | extern int tau_initialized; | ||
77 | extern int tau_interrupts(int); | ||
78 | #endif | ||
79 | |||
80 | int show_interrupts(struct seq_file *p, void *v) | ||
81 | { | ||
82 | int i = *(loff_t *) v, j; | ||
83 | struct irqaction * action; | ||
84 | unsigned long flags; | ||
85 | |||
86 | if (i == 0) { | ||
87 | seq_puts(p, " "); | ||
88 | for (j=0; j<NR_CPUS; j++) | ||
89 | if (cpu_online(j)) | ||
90 | seq_printf(p, "CPU%d ", j); | ||
91 | seq_putc(p, '\n'); | ||
92 | } | ||
93 | |||
94 | if (i < NR_IRQS) { | ||
95 | spin_lock_irqsave(&irq_desc[i].lock, flags); | ||
96 | action = irq_desc[i].action; | ||
97 | if ( !action || !action->handler ) | ||
98 | goto skip; | ||
99 | seq_printf(p, "%3d: ", i); | ||
100 | #ifdef CONFIG_SMP | ||
101 | for (j = 0; j < NR_CPUS; j++) | ||
102 | if (cpu_online(j)) | ||
103 | seq_printf(p, "%10u ", | ||
104 | kstat_cpu(j).irqs[i]); | ||
105 | #else | ||
106 | seq_printf(p, "%10u ", kstat_irqs(i)); | ||
107 | #endif /* CONFIG_SMP */ | ||
108 | if (irq_desc[i].handler) | ||
109 | seq_printf(p, " %s ", irq_desc[i].handler->typename); | ||
110 | else | ||
111 | seq_puts(p, " None "); | ||
112 | seq_printf(p, "%s", (irq_desc[i].status & IRQ_LEVEL) ? "Level " : "Edge "); | ||
113 | seq_printf(p, " %s", action->name); | ||
114 | for (action = action->next; action; action = action->next) | ||
115 | seq_printf(p, ", %s", action->name); | ||
116 | seq_putc(p, '\n'); | ||
117 | skip: | ||
118 | spin_unlock_irqrestore(&irq_desc[i].lock, flags); | ||
119 | } else if (i == NR_IRQS) { | ||
120 | #ifdef CONFIG_TAU_INT | ||
121 | if (tau_initialized){ | ||
122 | seq_puts(p, "TAU: "); | ||
123 | for (j = 0; j < NR_CPUS; j++) | ||
124 | if (cpu_online(j)) | ||
125 | seq_printf(p, "%10u ", tau_interrupts(j)); | ||
126 | seq_puts(p, " PowerPC Thermal Assist (cpu temp)\n"); | ||
127 | } | ||
128 | #endif | ||
129 | #if defined(CONFIG_SMP) && !defined(CONFIG_PPC_MERGE) | ||
130 | /* should this be per processor send/receive? */ | ||
131 | seq_printf(p, "IPI (recv/sent): %10u/%u\n", | ||
132 | atomic_read(&ipi_recv), atomic_read(&ipi_sent)); | ||
133 | #endif | ||
134 | seq_printf(p, "BAD: %10u\n", ppc_spurious_interrupts); | ||
135 | } | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | void do_IRQ(struct pt_regs *regs) | ||
140 | { | ||
141 | int irq, first = 1; | ||
142 | irq_enter(); | ||
143 | |||
144 | /* | ||
145 | * Every platform is required to implement ppc_md.get_irq. | ||
146 | * This function will either return an irq number or -1 to | ||
147 | * indicate there are no more pending. But the first time | ||
148 | * through the loop this means there wasn't and IRQ pending. | ||
149 | * The value -2 is for buggy hardware and means that this IRQ | ||
150 | * has already been handled. -- Tom | ||
151 | */ | ||
152 | while ((irq = ppc_md.get_irq(regs)) >= 0) { | ||
153 | __do_IRQ(irq, regs); | ||
154 | first = 0; | ||
155 | } | ||
156 | if (irq != -2 && first) | ||
157 | /* That's not SMP safe ... but who cares ? */ | ||
158 | ppc_spurious_interrupts++; | ||
159 | irq_exit(); | ||
160 | } | ||
161 | |||
162 | void __init init_IRQ(void) | ||
163 | { | ||
164 | ppc_md.init_IRQ(); | ||
165 | } | ||
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index ae6af29938a1..5e61124581d0 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S | |||
@@ -497,9 +497,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) | |||
497 | * and invalidate the corresponding instruction cache blocks. | 497 | * and invalidate the corresponding instruction cache blocks. |
498 | * This is a no-op on the 601. | 498 | * This is a no-op on the 601. |
499 | * | 499 | * |
500 | * flush_icache_range(unsigned long start, unsigned long stop) | 500 | * __flush_icache_range(unsigned long start, unsigned long stop) |
501 | */ | 501 | */ |
502 | _GLOBAL(flush_icache_range) | 502 | _GLOBAL(__flush_icache_range) |
503 | BEGIN_FTR_SECTION | 503 | BEGIN_FTR_SECTION |
504 | blr /* for 601, do nothing */ | 504 | blr /* for 601, do nothing */ |
505 | END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) | 505 | END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) |
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index e0ca61b37f4f..66073f775193 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <asm/btext.h> | 46 | #include <asm/btext.h> |
47 | #include <asm/div64.h> | 47 | #include <asm/div64.h> |
48 | #include <asm/xmon.h> | 48 | #include <asm/xmon.h> |
49 | #include <asm/signal.h> | ||
49 | 50 | ||
50 | #ifdef CONFIG_8xx | 51 | #ifdef CONFIG_8xx |
51 | #include <asm/commproc.h> | 52 | #include <asm/commproc.h> |
@@ -57,7 +58,6 @@ extern void machine_check_exception(struct pt_regs *regs); | |||
57 | extern void alignment_exception(struct pt_regs *regs); | 58 | extern void alignment_exception(struct pt_regs *regs); |
58 | extern void program_check_exception(struct pt_regs *regs); | 59 | extern void program_check_exception(struct pt_regs *regs); |
59 | extern void single_step_exception(struct pt_regs *regs); | 60 | extern void single_step_exception(struct pt_regs *regs); |
60 | extern int do_signal(sigset_t *, struct pt_regs *); | ||
61 | extern int pmac_newworld; | 61 | extern int pmac_newworld; |
62 | extern int sys_sigreturn(struct pt_regs *regs); | 62 | extern int sys_sigreturn(struct pt_regs *regs); |
63 | 63 | ||
@@ -78,7 +78,6 @@ EXPORT_SYMBOL(program_check_exception); | |||
78 | EXPORT_SYMBOL(single_step_exception); | 78 | EXPORT_SYMBOL(single_step_exception); |
79 | EXPORT_SYMBOL(sys_sigreturn); | 79 | EXPORT_SYMBOL(sys_sigreturn); |
80 | EXPORT_SYMBOL(ppc_n_lost_interrupts); | 80 | EXPORT_SYMBOL(ppc_n_lost_interrupts); |
81 | EXPORT_SYMBOL(ppc_lost_interrupts); | ||
82 | 81 | ||
83 | EXPORT_SYMBOL(ISA_DMA_THRESHOLD); | 82 | EXPORT_SYMBOL(ISA_DMA_THRESHOLD); |
84 | EXPORT_SYMBOL(DMA_MODE_READ); | 83 | EXPORT_SYMBOL(DMA_MODE_READ); |
@@ -176,6 +175,7 @@ EXPORT_SYMBOL(pci_bus_to_phys); | |||
176 | #endif /* CONFIG_PCI */ | 175 | #endif /* CONFIG_PCI */ |
177 | 176 | ||
178 | #ifdef CONFIG_NOT_COHERENT_CACHE | 177 | #ifdef CONFIG_NOT_COHERENT_CACHE |
178 | extern void flush_dcache_all(void); | ||
179 | EXPORT_SYMBOL(flush_dcache_all); | 179 | EXPORT_SYMBOL(flush_dcache_all); |
180 | #endif | 180 | #endif |
181 | 181 | ||
@@ -217,9 +217,6 @@ EXPORT_SYMBOL(adb_try_handler_change); | |||
217 | EXPORT_SYMBOL(cuda_request); | 217 | EXPORT_SYMBOL(cuda_request); |
218 | EXPORT_SYMBOL(cuda_poll); | 218 | EXPORT_SYMBOL(cuda_poll); |
219 | #endif /* CONFIG_ADB_CUDA */ | 219 | #endif /* CONFIG_ADB_CUDA */ |
220 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
221 | EXPORT_SYMBOL(_machine); | ||
222 | #endif | ||
223 | #ifdef CONFIG_PPC_PMAC | 220 | #ifdef CONFIG_PPC_PMAC |
224 | EXPORT_SYMBOL(sys_ctrler); | 221 | EXPORT_SYMBOL(sys_ctrler); |
225 | EXPORT_SYMBOL(pmac_newworld); | 222 | EXPORT_SYMBOL(pmac_newworld); |
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 6bcb85d2b7fd..dc55e1abc45b 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c | |||
@@ -76,6 +76,7 @@ unsigned int DMA_MODE_WRITE; | |||
76 | 76 | ||
77 | #ifdef CONFIG_PPC_MULTIPLATFORM | 77 | #ifdef CONFIG_PPC_MULTIPLATFORM |
78 | int _machine = 0; | 78 | int _machine = 0; |
79 | EXPORT_SYMBOL(_machine); | ||
79 | 80 | ||
80 | extern void prep_init(unsigned long r3, unsigned long r4, | 81 | extern void prep_init(unsigned long r3, unsigned long r4, |
81 | unsigned long r5, unsigned long r6, unsigned long r7); | 82 | unsigned long r5, unsigned long r6, unsigned long r7); |
diff --git a/arch/ppc/platforms/pmac_pic.c b/arch/ppc/platforms/pmac_pic.c index 9f2d95ea8564..4742bf609357 100644 --- a/arch/ppc/platforms/pmac_pic.c +++ b/arch/ppc/platforms/pmac_pic.c | |||
@@ -75,6 +75,9 @@ static DEFINE_SPINLOCK(pmac_pic_lock); | |||
75 | #define GATWICK_IRQ_POOL_SIZE 10 | 75 | #define GATWICK_IRQ_POOL_SIZE 10 |
76 | static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE]; | 76 | static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE]; |
77 | 77 | ||
78 | #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) | ||
79 | static unsigned long ppc_lost_interrupts[NR_MASK_WORDS]; | ||
80 | |||
78 | /* | 81 | /* |
79 | * Mark an irq as "lost". This is only used on the pmac | 82 | * Mark an irq as "lost". This is only used on the pmac |
80 | * since it can lose interrupts (see pmac_set_irq_mask). | 83 | * since it can lose interrupts (see pmac_set_irq_mask). |
diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c index 067d7d53b81e..4415748071dc 100644 --- a/arch/ppc/platforms/prep_setup.c +++ b/arch/ppc/platforms/prep_setup.c | |||
@@ -61,6 +61,15 @@ | |||
61 | #include <asm/pci-bridge.h> | 61 | #include <asm/pci-bridge.h> |
62 | #include <asm/todc.h> | 62 | #include <asm/todc.h> |
63 | 63 | ||
64 | /* prep registers for L2 */ | ||
65 | #define CACHECRBA 0x80000823 /* Cache configuration register address */ | ||
66 | #define L2CACHE_MASK 0x03 /* Mask for 2 L2 Cache bits */ | ||
67 | #define L2CACHE_512KB 0x00 /* 512KB */ | ||
68 | #define L2CACHE_256KB 0x01 /* 256KB */ | ||
69 | #define L2CACHE_1MB 0x02 /* 1MB */ | ||
70 | #define L2CACHE_NONE 0x03 /* NONE */ | ||
71 | #define L2CACHE_PARITY 0x08 /* Mask for L2 Cache Parity Protected bit */ | ||
72 | |||
64 | TODC_ALLOC(); | 73 | TODC_ALLOC(); |
65 | 74 | ||
66 | unsigned char ucSystemType; | 75 | unsigned char ucSystemType; |
diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig index 29552348e581..c9d32db9d76a 100644 --- a/arch/ppc64/Kconfig +++ b/arch/ppc64/Kconfig | |||
@@ -297,6 +297,10 @@ config HAVE_ARCH_EARLY_PFN_TO_NID | |||
297 | def_bool y | 297 | def_bool y |
298 | depends on NEED_MULTIPLE_NODES | 298 | depends on NEED_MULTIPLE_NODES |
299 | 299 | ||
300 | config ARCH_MEMORY_PROBE | ||
301 | def_bool y | ||
302 | depends on MEMORY_HOTPLUG | ||
303 | |||
300 | # Some NUMA nodes have memory ranges that span | 304 | # Some NUMA nodes have memory ranges that span |
301 | # other nodes. Even though a pfn is valid and | 305 | # other nodes. Even though a pfn is valid and |
302 | # between a node's start and end pfns, it may not | 306 | # between a node's start and end pfns, it may not |
diff --git a/arch/ppc64/boot/addRamDisk.c b/arch/ppc64/boot/addRamDisk.c index 7f2c09473394..c02a99952be7 100644 --- a/arch/ppc64/boot/addRamDisk.c +++ b/arch/ppc64/boot/addRamDisk.c | |||
@@ -5,11 +5,59 @@ | |||
5 | #include <sys/types.h> | 5 | #include <sys/types.h> |
6 | #include <sys/stat.h> | 6 | #include <sys/stat.h> |
7 | #include <string.h> | 7 | #include <string.h> |
8 | #include <elf.h> | ||
8 | 9 | ||
9 | #define ElfHeaderSize (64 * 1024) | 10 | #define ElfHeaderSize (64 * 1024) |
10 | #define ElfPages (ElfHeaderSize / 4096) | 11 | #define ElfPages (ElfHeaderSize / 4096) |
11 | #define KERNELBASE (0xc000000000000000) | 12 | #define KERNELBASE (0xc000000000000000) |
13 | #define _ALIGN_UP(addr,size) (((addr)+((size)-1))&(~((size)-1))) | ||
12 | 14 | ||
15 | struct addr_range { | ||
16 | unsigned long long addr; | ||
17 | unsigned long memsize; | ||
18 | unsigned long offset; | ||
19 | }; | ||
20 | |||
21 | static int check_elf64(void *p, int size, struct addr_range *r) | ||
22 | { | ||
23 | Elf64_Ehdr *elf64 = p; | ||
24 | Elf64_Phdr *elf64ph; | ||
25 | |||
26 | if (elf64->e_ident[EI_MAG0] != ELFMAG0 || | ||
27 | elf64->e_ident[EI_MAG1] != ELFMAG1 || | ||
28 | elf64->e_ident[EI_MAG2] != ELFMAG2 || | ||
29 | elf64->e_ident[EI_MAG3] != ELFMAG3 || | ||
30 | elf64->e_ident[EI_CLASS] != ELFCLASS64 || | ||
31 | elf64->e_ident[EI_DATA] != ELFDATA2MSB || | ||
32 | elf64->e_type != ET_EXEC || elf64->e_machine != EM_PPC64) | ||
33 | return 0; | ||
34 | |||
35 | if ((elf64->e_phoff + sizeof(Elf64_Phdr)) > size) | ||
36 | return 0; | ||
37 | |||
38 | elf64ph = (Elf64_Phdr *) ((unsigned long)elf64 + | ||
39 | (unsigned long)elf64->e_phoff); | ||
40 | |||
41 | r->memsize = (unsigned long)elf64ph->p_memsz; | ||
42 | r->offset = (unsigned long)elf64ph->p_offset; | ||
43 | r->addr = (unsigned long long)elf64ph->p_vaddr; | ||
44 | |||
45 | #ifdef DEBUG | ||
46 | printf("PPC64 ELF file, ph:\n"); | ||
47 | printf("p_type 0x%08x\n", elf64ph->p_type); | ||
48 | printf("p_flags 0x%08x\n", elf64ph->p_flags); | ||
49 | printf("p_offset 0x%016llx\n", elf64ph->p_offset); | ||
50 | printf("p_vaddr 0x%016llx\n", elf64ph->p_vaddr); | ||
51 | printf("p_paddr 0x%016llx\n", elf64ph->p_paddr); | ||
52 | printf("p_filesz 0x%016llx\n", elf64ph->p_filesz); | ||
53 | printf("p_memsz 0x%016llx\n", elf64ph->p_memsz); | ||
54 | printf("p_align 0x%016llx\n", elf64ph->p_align); | ||
55 | printf("... skipping 0x%08lx bytes of ELF header\n", | ||
56 | (unsigned long)elf64ph->p_offset); | ||
57 | #endif | ||
58 | |||
59 | return 64; | ||
60 | } | ||
13 | void get4k(FILE *file, char *buf ) | 61 | void get4k(FILE *file, char *buf ) |
14 | { | 62 | { |
15 | unsigned j; | 63 | unsigned j; |
@@ -34,97 +82,92 @@ void death(const char *msg, FILE *fdesc, const char *fname) | |||
34 | int main(int argc, char **argv) | 82 | int main(int argc, char **argv) |
35 | { | 83 | { |
36 | char inbuf[4096]; | 84 | char inbuf[4096]; |
37 | FILE *ramDisk = NULL; | 85 | struct addr_range vmlinux; |
38 | FILE *sysmap = NULL; | 86 | FILE *ramDisk; |
39 | FILE *inputVmlinux = NULL; | 87 | FILE *inputVmlinux; |
40 | FILE *outputVmlinux = NULL; | 88 | FILE *outputVmlinux; |
41 | 89 | ||
42 | unsigned i = 0; | 90 | char *rd_name, *lx_name, *out_name; |
43 | unsigned long ramFileLen = 0; | 91 | |
44 | unsigned long ramLen = 0; | 92 | size_t i; |
45 | unsigned long roundR = 0; | 93 | unsigned long ramFileLen; |
46 | 94 | unsigned long ramLen; | |
47 | unsigned long sysmapFileLen = 0; | 95 | unsigned long roundR; |
48 | unsigned long sysmapLen = 0; | 96 | unsigned long offset_end; |
49 | unsigned long sysmapPages = 0; | 97 | |
50 | char* ptr_end = NULL; | 98 | unsigned long kernelLen; |
51 | unsigned long offset_end = 0; | 99 | unsigned long actualKernelLen; |
52 | 100 | unsigned long round; | |
53 | unsigned long kernelLen = 0; | 101 | unsigned long roundedKernelLen; |
54 | unsigned long actualKernelLen = 0; | 102 | unsigned long ramStartOffs; |
55 | unsigned long round = 0; | 103 | unsigned long ramPages; |
56 | unsigned long roundedKernelLen = 0; | 104 | unsigned long roundedKernelPages; |
57 | unsigned long ramStartOffs = 0; | 105 | unsigned long hvReleaseData; |
58 | unsigned long ramPages = 0; | ||
59 | unsigned long roundedKernelPages = 0; | ||
60 | unsigned long hvReleaseData = 0; | ||
61 | u_int32_t eyeCatcher = 0xc8a5d9c4; | 106 | u_int32_t eyeCatcher = 0xc8a5d9c4; |
62 | unsigned long naca = 0; | 107 | unsigned long naca; |
63 | unsigned long xRamDisk = 0; | 108 | unsigned long xRamDisk; |
64 | unsigned long xRamDiskSize = 0; | 109 | unsigned long xRamDiskSize; |
65 | long padPages = 0; | 110 | long padPages; |
66 | 111 | ||
67 | 112 | ||
68 | if (argc < 2) { | 113 | if (argc < 2) { |
69 | fprintf(stderr, "Name of RAM disk file missing.\n"); | 114 | fprintf(stderr, "Name of RAM disk file missing.\n"); |
70 | exit(1); | 115 | exit(1); |
71 | } | 116 | } |
117 | rd_name = argv[1]; | ||
72 | 118 | ||
73 | if (argc < 3) { | 119 | if (argc < 3) { |
74 | fprintf(stderr, "Name of System Map input file is missing.\n"); | ||
75 | exit(1); | ||
76 | } | ||
77 | |||
78 | if (argc < 4) { | ||
79 | fprintf(stderr, "Name of vmlinux file missing.\n"); | 120 | fprintf(stderr, "Name of vmlinux file missing.\n"); |
80 | exit(1); | 121 | exit(1); |
81 | } | 122 | } |
123 | lx_name = argv[2]; | ||
82 | 124 | ||
83 | if (argc < 5) { | 125 | if (argc < 4) { |
84 | fprintf(stderr, "Name of vmlinux output file missing.\n"); | 126 | fprintf(stderr, "Name of vmlinux output file missing.\n"); |
85 | exit(1); | 127 | exit(1); |
86 | } | 128 | } |
129 | out_name = argv[3]; | ||
87 | 130 | ||
88 | 131 | ||
89 | ramDisk = fopen(argv[1], "r"); | 132 | ramDisk = fopen(rd_name, "r"); |
90 | if ( ! ramDisk ) { | 133 | if ( ! ramDisk ) { |
91 | fprintf(stderr, "RAM disk file \"%s\" failed to open.\n", argv[1]); | 134 | fprintf(stderr, "RAM disk file \"%s\" failed to open.\n", rd_name); |
92 | exit(1); | 135 | exit(1); |
93 | } | 136 | } |
94 | 137 | ||
95 | sysmap = fopen(argv[2], "r"); | 138 | inputVmlinux = fopen(lx_name, "r"); |
96 | if ( ! sysmap ) { | ||
97 | fprintf(stderr, "System Map file \"%s\" failed to open.\n", argv[2]); | ||
98 | exit(1); | ||
99 | } | ||
100 | |||
101 | inputVmlinux = fopen(argv[3], "r"); | ||
102 | if ( ! inputVmlinux ) { | 139 | if ( ! inputVmlinux ) { |
103 | fprintf(stderr, "vmlinux file \"%s\" failed to open.\n", argv[3]); | 140 | fprintf(stderr, "vmlinux file \"%s\" failed to open.\n", lx_name); |
104 | exit(1); | 141 | exit(1); |
105 | } | 142 | } |
106 | 143 | ||
107 | outputVmlinux = fopen(argv[4], "w+"); | 144 | outputVmlinux = fopen(out_name, "w+"); |
108 | if ( ! outputVmlinux ) { | 145 | if ( ! outputVmlinux ) { |
109 | fprintf(stderr, "output vmlinux file \"%s\" failed to open.\n", argv[4]); | 146 | fprintf(stderr, "output vmlinux file \"%s\" failed to open.\n", out_name); |
110 | exit(1); | 147 | exit(1); |
111 | } | 148 | } |
112 | 149 | ||
113 | 150 | i = fread(inbuf, 1, sizeof(inbuf), inputVmlinux); | |
114 | 151 | if (i != sizeof(inbuf)) { | |
152 | fprintf(stderr, "can not read vmlinux file %s: %u\n", lx_name, i); | ||
153 | exit(1); | ||
154 | } | ||
155 | |||
156 | i = check_elf64(inbuf, sizeof(inbuf), &vmlinux); | ||
157 | if (i == 0) { | ||
158 | fprintf(stderr, "You must have a linux kernel specified as argv[2]\n"); | ||
159 | exit(1); | ||
160 | } | ||
161 | |||
115 | /* Input Vmlinux file */ | 162 | /* Input Vmlinux file */ |
116 | fseek(inputVmlinux, 0, SEEK_END); | 163 | fseek(inputVmlinux, 0, SEEK_END); |
117 | kernelLen = ftell(inputVmlinux); | 164 | kernelLen = ftell(inputVmlinux); |
118 | fseek(inputVmlinux, 0, SEEK_SET); | 165 | fseek(inputVmlinux, 0, SEEK_SET); |
119 | printf("kernel file size = %d\n", kernelLen); | 166 | printf("kernel file size = %lu\n", kernelLen); |
120 | if ( kernelLen == 0 ) { | ||
121 | fprintf(stderr, "You must have a linux kernel specified as argv[3]\n"); | ||
122 | exit(1); | ||
123 | } | ||
124 | 167 | ||
125 | actualKernelLen = kernelLen - ElfHeaderSize; | 168 | actualKernelLen = kernelLen - ElfHeaderSize; |
126 | 169 | ||
127 | printf("actual kernel length (minus ELF header) = %d\n", actualKernelLen); | 170 | printf("actual kernel length (minus ELF header) = %lu\n", actualKernelLen); |
128 | 171 | ||
129 | round = actualKernelLen % 4096; | 172 | round = actualKernelLen % 4096; |
130 | roundedKernelLen = actualKernelLen; | 173 | roundedKernelLen = actualKernelLen; |
@@ -134,39 +177,7 @@ int main(int argc, char **argv) | |||
134 | roundedKernelPages = roundedKernelLen / 4096; | 177 | roundedKernelPages = roundedKernelLen / 4096; |
135 | printf("Vmlinux pages to copy = %ld/0x%lx \n", roundedKernelPages, roundedKernelPages); | 178 | printf("Vmlinux pages to copy = %ld/0x%lx \n", roundedKernelPages, roundedKernelPages); |
136 | 179 | ||
137 | 180 | offset_end = _ALIGN_UP(vmlinux.memsize, 4096); | |
138 | |||
139 | /* Input System Map file */ | ||
140 | /* (needs to be processed simply to determine if we need to add pad pages due to the static variables not being included in the vmlinux) */ | ||
141 | fseek(sysmap, 0, SEEK_END); | ||
142 | sysmapFileLen = ftell(sysmap); | ||
143 | fseek(sysmap, 0, SEEK_SET); | ||
144 | printf("%s file size = %ld/0x%lx \n", argv[2], sysmapFileLen, sysmapFileLen); | ||
145 | |||
146 | sysmapLen = sysmapFileLen; | ||
147 | |||
148 | roundR = 4096 - (sysmapLen % 4096); | ||
149 | if (roundR) { | ||
150 | printf("Rounding System Map file up to a multiple of 4096, adding %ld/0x%lx \n", roundR, roundR); | ||
151 | sysmapLen += roundR; | ||
152 | } | ||
153 | printf("Rounded System Map size is %ld/0x%lx \n", sysmapLen, sysmapLen); | ||
154 | |||
155 | /* Process the Sysmap file to determine where _end is */ | ||
156 | sysmapPages = sysmapLen / 4096; | ||
157 | /* read the whole file line by line, expect that it doesn't fail */ | ||
158 | while ( fgets(inbuf, 4096, sysmap) ) ; | ||
159 | /* search for _end in the last page of the system map */ | ||
160 | ptr_end = strstr(inbuf, " _end"); | ||
161 | if (!ptr_end) { | ||
162 | fprintf(stderr, "Unable to find _end in the sysmap file \n"); | ||
163 | fprintf(stderr, "inbuf: \n"); | ||
164 | fprintf(stderr, "%s \n", inbuf); | ||
165 | exit(1); | ||
166 | } | ||
167 | printf("Found _end in the last page of the sysmap - backing up 10 characters it looks like %s", ptr_end-10); | ||
168 | /* convert address of _end in system map to hex offset. */ | ||
169 | offset_end = (unsigned int)strtol(ptr_end-10, NULL, 16); | ||
170 | /* calc how many pages we need to insert between the vmlinux and the start of the ram disk */ | 181 | /* calc how many pages we need to insert between the vmlinux and the start of the ram disk */ |
171 | padPages = offset_end/4096 - roundedKernelPages; | 182 | padPages = offset_end/4096 - roundedKernelPages; |
172 | 183 | ||
@@ -194,7 +205,7 @@ int main(int argc, char **argv) | |||
194 | fseek(ramDisk, 0, SEEK_END); | 205 | fseek(ramDisk, 0, SEEK_END); |
195 | ramFileLen = ftell(ramDisk); | 206 | ramFileLen = ftell(ramDisk); |
196 | fseek(ramDisk, 0, SEEK_SET); | 207 | fseek(ramDisk, 0, SEEK_SET); |
197 | printf("%s file size = %ld/0x%lx \n", argv[1], ramFileLen, ramFileLen); | 208 | printf("%s file size = %ld/0x%lx \n", rd_name, ramFileLen, ramFileLen); |
198 | 209 | ||
199 | ramLen = ramFileLen; | 210 | ramLen = ramFileLen; |
200 | 211 | ||
@@ -248,19 +259,19 @@ int main(int argc, char **argv) | |||
248 | /* fseek to the hvReleaseData pointer */ | 259 | /* fseek to the hvReleaseData pointer */ |
249 | fseek(outputVmlinux, ElfHeaderSize + 0x24, SEEK_SET); | 260 | fseek(outputVmlinux, ElfHeaderSize + 0x24, SEEK_SET); |
250 | if (fread(&hvReleaseData, 4, 1, outputVmlinux) != 1) { | 261 | if (fread(&hvReleaseData, 4, 1, outputVmlinux) != 1) { |
251 | death("Could not read hvReleaseData pointer\n", outputVmlinux, argv[4]); | 262 | death("Could not read hvReleaseData pointer\n", outputVmlinux, out_name); |
252 | } | 263 | } |
253 | hvReleaseData = ntohl(hvReleaseData); /* Convert to native int */ | 264 | hvReleaseData = ntohl(hvReleaseData); /* Convert to native int */ |
254 | printf("hvReleaseData is at %08x\n", hvReleaseData); | 265 | printf("hvReleaseData is at %08lx\n", hvReleaseData); |
255 | 266 | ||
256 | /* fseek to the hvReleaseData */ | 267 | /* fseek to the hvReleaseData */ |
257 | fseek(outputVmlinux, ElfHeaderSize + hvReleaseData, SEEK_SET); | 268 | fseek(outputVmlinux, ElfHeaderSize + hvReleaseData, SEEK_SET); |
258 | if (fread(inbuf, 0x40, 1, outputVmlinux) != 1) { | 269 | if (fread(inbuf, 0x40, 1, outputVmlinux) != 1) { |
259 | death("Could not read hvReleaseData\n", outputVmlinux, argv[4]); | 270 | death("Could not read hvReleaseData\n", outputVmlinux, out_name); |
260 | } | 271 | } |
261 | /* Check hvReleaseData sanity */ | 272 | /* Check hvReleaseData sanity */ |
262 | if (memcmp(inbuf, &eyeCatcher, 4) != 0) { | 273 | if (memcmp(inbuf, &eyeCatcher, 4) != 0) { |
263 | death("hvReleaseData is invalid\n", outputVmlinux, argv[4]); | 274 | death("hvReleaseData is invalid\n", outputVmlinux, out_name); |
264 | } | 275 | } |
265 | /* Get the naca pointer */ | 276 | /* Get the naca pointer */ |
266 | naca = ntohl(*((u_int32_t*) &inbuf[0x0C])) - KERNELBASE; | 277 | naca = ntohl(*((u_int32_t*) &inbuf[0x0C])) - KERNELBASE; |
@@ -269,13 +280,13 @@ int main(int argc, char **argv) | |||
269 | /* fseek to the naca */ | 280 | /* fseek to the naca */ |
270 | fseek(outputVmlinux, ElfHeaderSize + naca, SEEK_SET); | 281 | fseek(outputVmlinux, ElfHeaderSize + naca, SEEK_SET); |
271 | if (fread(inbuf, 0x18, 1, outputVmlinux) != 1) { | 282 | if (fread(inbuf, 0x18, 1, outputVmlinux) != 1) { |
272 | death("Could not read naca\n", outputVmlinux, argv[4]); | 283 | death("Could not read naca\n", outputVmlinux, out_name); |
273 | } | 284 | } |
274 | xRamDisk = ntohl(*((u_int32_t *) &inbuf[0x0c])); | 285 | xRamDisk = ntohl(*((u_int32_t *) &inbuf[0x0c])); |
275 | xRamDiskSize = ntohl(*((u_int32_t *) &inbuf[0x14])); | 286 | xRamDiskSize = ntohl(*((u_int32_t *) &inbuf[0x14])); |
276 | /* Make sure a RAM disk isn't already present */ | 287 | /* Make sure a RAM disk isn't already present */ |
277 | if ((xRamDisk != 0) || (xRamDiskSize != 0)) { | 288 | if ((xRamDisk != 0) || (xRamDiskSize != 0)) { |
278 | death("RAM disk is already attached to this kernel\n", outputVmlinux, argv[4]); | 289 | death("RAM disk is already attached to this kernel\n", outputVmlinux, out_name); |
279 | } | 290 | } |
280 | /* Fill in the values */ | 291 | /* Fill in the values */ |
281 | *((u_int32_t *) &inbuf[0x0c]) = htonl(ramStartOffs); | 292 | *((u_int32_t *) &inbuf[0x0c]) = htonl(ramStartOffs); |
@@ -285,15 +296,15 @@ int main(int argc, char **argv) | |||
285 | fflush(outputVmlinux); | 296 | fflush(outputVmlinux); |
286 | fseek(outputVmlinux, ElfHeaderSize + naca, SEEK_SET); | 297 | fseek(outputVmlinux, ElfHeaderSize + naca, SEEK_SET); |
287 | if (fwrite(inbuf, 0x18, 1, outputVmlinux) != 1) { | 298 | if (fwrite(inbuf, 0x18, 1, outputVmlinux) != 1) { |
288 | death("Could not write naca\n", outputVmlinux, argv[4]); | 299 | death("Could not write naca\n", outputVmlinux, out_name); |
289 | } | 300 | } |
290 | printf("Ram Disk of 0x%lx pages is attached to the kernel at offset 0x%08x\n", | 301 | printf("Ram Disk of 0x%lx pages is attached to the kernel at offset 0x%08lx\n", |
291 | ramPages, ramStartOffs); | 302 | ramPages, ramStartOffs); |
292 | 303 | ||
293 | /* Done */ | 304 | /* Done */ |
294 | fclose(outputVmlinux); | 305 | fclose(outputVmlinux); |
295 | /* Set permission to executable */ | 306 | /* Set permission to executable */ |
296 | chmod(argv[4], S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); | 307 | chmod(out_name, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); |
297 | 308 | ||
298 | return 0; | 309 | return 0; |
299 | } | 310 | } |
diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index c441aebe7648..58b19f107656 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile | |||
@@ -11,12 +11,11 @@ obj-y := misc.o prom.o | |||
11 | 11 | ||
12 | endif | 12 | endif |
13 | 13 | ||
14 | obj-y += irq.o idle.o dma.o \ | 14 | obj-y += idle.o dma.o \ |
15 | align.o pacaData.o \ | 15 | align.o \ |
16 | udbg.o ioctl32.o \ | 16 | udbg.o \ |
17 | rtc.o \ | 17 | rtc.o \ |
18 | cpu_setup_power4.o \ | 18 | iommu.o vdso.o |
19 | iommu.o sysfs.o vdso.o firmware.o | ||
20 | obj-y += vdso32/ vdso64/ | 19 | obj-y += vdso32/ vdso64/ |
21 | 20 | ||
22 | pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o | 21 | pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o |
@@ -31,15 +30,10 @@ endif | |||
31 | obj-$(CONFIG_PPC_PSERIES) += udbg_16550.o | 30 | obj-$(CONFIG_PPC_PSERIES) += udbg_16550.o |
32 | 31 | ||
33 | obj-$(CONFIG_KEXEC) += machine_kexec.o | 32 | obj-$(CONFIG_KEXEC) += machine_kexec.o |
34 | obj-$(CONFIG_EEH) += eeh.o | ||
35 | obj-$(CONFIG_PROC_FS) += proc_ppc64.o | ||
36 | obj-$(CONFIG_MODULES) += module.o | 33 | obj-$(CONFIG_MODULES) += module.o |
37 | ifneq ($(CONFIG_PPC_MERGE),y) | 34 | ifneq ($(CONFIG_PPC_MERGE),y) |
38 | obj-$(CONFIG_MODULES) += ppc_ksyms.o | 35 | obj-$(CONFIG_MODULES) += ppc_ksyms.o |
39 | endif | 36 | endif |
40 | obj-$(CONFIG_PPC_RTAS) += rtas_pci.o | ||
41 | obj-$(CONFIG_SCANLOG) += scanlog.o | ||
42 | obj-$(CONFIG_LPARCFG) += lparcfg.o | ||
43 | obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o | 37 | obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o |
44 | ifneq ($(CONFIG_PPC_MERGE),y) | 38 | ifneq ($(CONFIG_PPC_MERGE),y) |
45 | obj-$(CONFIG_BOOTX_TEXT) += btext.o | 39 | obj-$(CONFIG_BOOTX_TEXT) += btext.o |
@@ -52,8 +46,6 @@ obj-$(CONFIG_PPC_MAPLE) += udbg_16550.o | |||
52 | 46 | ||
53 | obj-$(CONFIG_KPROBES) += kprobes.o | 47 | obj-$(CONFIG_KPROBES) += kprobes.o |
54 | 48 | ||
55 | CFLAGS_ioctl32.o += -Ifs/ | ||
56 | |||
57 | ifneq ($(CONFIG_PPC_MERGE),y) | 49 | ifneq ($(CONFIG_PPC_MERGE),y) |
58 | ifeq ($(CONFIG_PPC_ISERIES),y) | 50 | ifeq ($(CONFIG_PPC_ISERIES),y) |
59 | arch/ppc64/kernel/head.o: arch/powerpc/kernel/lparmap.s | 51 | arch/ppc64/kernel/head.o: arch/powerpc/kernel/lparmap.s |
diff --git a/arch/ppc64/kernel/asm-offsets.c b/arch/ppc64/kernel/asm-offsets.c index bce9065da6cb..84ab5c18ef52 100644 --- a/arch/ppc64/kernel/asm-offsets.c +++ b/arch/ppc64/kernel/asm-offsets.c | |||
@@ -74,7 +74,6 @@ int main(void) | |||
74 | DEFINE(ICACHEL1LINESIZE, offsetof(struct ppc64_caches, iline_size)); | 74 | DEFINE(ICACHEL1LINESIZE, offsetof(struct ppc64_caches, iline_size)); |
75 | DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_iline_size)); | 75 | DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_iline_size)); |
76 | DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, ilines_per_page)); | 76 | DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, ilines_per_page)); |
77 | DEFINE(PLATFORM, offsetof(struct systemcfg, platform)); | ||
78 | DEFINE(PLATFORM_LPAR, PLATFORM_LPAR); | 77 | DEFINE(PLATFORM_LPAR, PLATFORM_LPAR); |
79 | 78 | ||
80 | /* paca */ | 79 | /* paca */ |
diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S index 9e8050ea1225..1c869ea72d28 100644 --- a/arch/ppc64/kernel/head.S +++ b/arch/ppc64/kernel/head.S | |||
@@ -28,7 +28,6 @@ | |||
28 | #include <asm/processor.h> | 28 | #include <asm/processor.h> |
29 | #include <asm/page.h> | 29 | #include <asm/page.h> |
30 | #include <asm/mmu.h> | 30 | #include <asm/mmu.h> |
31 | #include <asm/systemcfg.h> | ||
32 | #include <asm/ppc_asm.h> | 31 | #include <asm/ppc_asm.h> |
33 | #include <asm/asm-offsets.h> | 32 | #include <asm/asm-offsets.h> |
34 | #include <asm/bug.h> | 33 | #include <asm/bug.h> |
@@ -1701,21 +1700,9 @@ _GLOBAL(__secondary_start) | |||
1701 | HMT_MEDIUM /* Set thread priority to MEDIUM */ | 1700 | HMT_MEDIUM /* Set thread priority to MEDIUM */ |
1702 | 1701 | ||
1703 | ld r2,PACATOC(r13) | 1702 | ld r2,PACATOC(r13) |
1704 | li r6,0 | 1703 | |
1705 | stb r6,PACAPROCENABLED(r13) | 1704 | /* Do early setup for that CPU */ |
1706 | 1705 | bl .early_setup_secondary | |
1707 | #ifndef CONFIG_PPC_ISERIES | ||
1708 | /* Initialize the page table pointer register. */ | ||
1709 | LOADADDR(r6,_SDR1) | ||
1710 | ld r6,0(r6) /* get the value of _SDR1 */ | ||
1711 | mtspr SPRN_SDR1,r6 /* set the htab location */ | ||
1712 | #endif | ||
1713 | /* Initialize the first segment table (or SLB) entry */ | ||
1714 | ld r3,PACASTABVIRT(r13) /* get addr of segment table */ | ||
1715 | BEGIN_FTR_SECTION | ||
1716 | bl .stab_initialize | ||
1717 | END_FTR_SECTION_IFCLR(CPU_FTR_SLB) | ||
1718 | bl .slb_initialize | ||
1719 | 1706 | ||
1720 | /* Initialize the kernel stack. Just a repeat for iSeries. */ | 1707 | /* Initialize the kernel stack. Just a repeat for iSeries. */ |
1721 | LOADADDR(r3,current_set) | 1708 | LOADADDR(r3,current_set) |
@@ -1724,37 +1711,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB) | |||
1724 | addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD | 1711 | addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD |
1725 | std r1,PACAKSAVE(r13) | 1712 | std r1,PACAKSAVE(r13) |
1726 | 1713 | ||
1727 | ld r3,PACASTABREAL(r13) /* get raddr of segment table */ | ||
1728 | ori r4,r3,1 /* turn on valid bit */ | ||
1729 | |||
1730 | #ifdef CONFIG_PPC_ISERIES | ||
1731 | li r0,-1 /* hypervisor call */ | ||
1732 | li r3,1 | ||
1733 | sldi r3,r3,63 /* 0x8000000000000000 */ | ||
1734 | ori r3,r3,4 /* 0x8000000000000004 */ | ||
1735 | sc /* HvCall_setASR */ | ||
1736 | #else | ||
1737 | /* set the ASR */ | ||
1738 | ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */ | ||
1739 | ld r3,0(r3) | ||
1740 | lwz r3,PLATFORM(r3) /* r3 = platform flags */ | ||
1741 | andi. r3,r3,PLATFORM_LPAR /* Test if bit 0 is set (LPAR bit) */ | ||
1742 | beq 98f /* branch if result is 0 */ | ||
1743 | mfspr r3,SPRN_PVR | ||
1744 | srwi r3,r3,16 | ||
1745 | cmpwi r3,0x37 /* SStar */ | ||
1746 | beq 97f | ||
1747 | cmpwi r3,0x36 /* IStar */ | ||
1748 | beq 97f | ||
1749 | cmpwi r3,0x34 /* Pulsar */ | ||
1750 | bne 98f | ||
1751 | 97: li r3,H_SET_ASR /* hcall = H_SET_ASR */ | ||
1752 | HVSC /* Invoking hcall */ | ||
1753 | b 99f | ||
1754 | 98: /* !(rpa hypervisor) || !(star) */ | ||
1755 | mtasr r4 /* set the stab location */ | ||
1756 | 99: | ||
1757 | #endif | ||
1758 | li r7,0 | 1714 | li r7,0 |
1759 | mtlr r7 | 1715 | mtlr r7 |
1760 | 1716 | ||
@@ -1896,40 +1852,6 @@ _STATIC(start_here_multiplatform) | |||
1896 | mr r3,r31 | 1852 | mr r3,r31 |
1897 | bl .early_setup | 1853 | bl .early_setup |
1898 | 1854 | ||
1899 | /* set the ASR */ | ||
1900 | ld r3,PACASTABREAL(r13) | ||
1901 | ori r4,r3,1 /* turn on valid bit */ | ||
1902 | ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */ | ||
1903 | ld r3,0(r3) | ||
1904 | lwz r3,PLATFORM(r3) /* r3 = platform flags */ | ||
1905 | andi. r3,r3,PLATFORM_LPAR /* Test if bit 0 is set (LPAR bit) */ | ||
1906 | beq 98f /* branch if result is 0 */ | ||
1907 | mfspr r3,SPRN_PVR | ||
1908 | srwi r3,r3,16 | ||
1909 | cmpwi r3,0x37 /* SStar */ | ||
1910 | beq 97f | ||
1911 | cmpwi r3,0x36 /* IStar */ | ||
1912 | beq 97f | ||
1913 | cmpwi r3,0x34 /* Pulsar */ | ||
1914 | bne 98f | ||
1915 | 97: li r3,H_SET_ASR /* hcall = H_SET_ASR */ | ||
1916 | HVSC /* Invoking hcall */ | ||
1917 | b 99f | ||
1918 | 98: /* !(rpa hypervisor) || !(star) */ | ||
1919 | mtasr r4 /* set the stab location */ | ||
1920 | 99: | ||
1921 | /* Set SDR1 (hash table pointer) */ | ||
1922 | ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */ | ||
1923 | ld r3,0(r3) | ||
1924 | lwz r3,PLATFORM(r3) /* r3 = platform flags */ | ||
1925 | /* Test if bit 0 is set (LPAR bit) */ | ||
1926 | andi. r3,r3,PLATFORM_LPAR | ||
1927 | bne 98f /* branch if result is !0 */ | ||
1928 | LOADADDR(r6,_SDR1) /* Only if NOT LPAR */ | ||
1929 | sub r6,r6,r26 | ||
1930 | ld r6,0(r6) /* get the value of _SDR1 */ | ||
1931 | mtspr SPRN_SDR1,r6 /* set the htab location */ | ||
1932 | 98: | ||
1933 | LOADADDR(r3,.start_here_common) | 1855 | LOADADDR(r3,.start_here_common) |
1934 | SET_REG_TO_CONST(r4, MSR_KERNEL) | 1856 | SET_REG_TO_CONST(r4, MSR_KERNEL) |
1935 | mtspr SPRN_SRR0,r3 | 1857 | mtspr SPRN_SRR0,r3 |
diff --git a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c index 715bc0e71e0f..b879d3057ef8 100644 --- a/arch/ppc64/kernel/idle.c +++ b/arch/ppc64/kernel/idle.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <asm/processor.h> | 26 | #include <asm/processor.h> |
27 | #include <asm/cputable.h> | 27 | #include <asm/cputable.h> |
28 | #include <asm/time.h> | 28 | #include <asm/time.h> |
29 | #include <asm/systemcfg.h> | ||
30 | #include <asm/machdep.h> | 29 | #include <asm/machdep.h> |
31 | #include <asm/smp.h> | 30 | #include <asm/smp.h> |
32 | 31 | ||
diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S index 914632ec587d..492bca6137eb 100644 --- a/arch/ppc64/kernel/misc.S +++ b/arch/ppc64/kernel/misc.S | |||
@@ -78,12 +78,12 @@ _GLOBAL(call_do_softirq) | |||
78 | mtlr r0 | 78 | mtlr r0 |
79 | blr | 79 | blr |
80 | 80 | ||
81 | _GLOBAL(call_handle_IRQ_event) | 81 | _GLOBAL(call___do_IRQ) |
82 | mflr r0 | 82 | mflr r0 |
83 | std r0,16(r1) | 83 | std r0,16(r1) |
84 | stdu r1,THREAD_SIZE-112(r6) | 84 | stdu r1,THREAD_SIZE-112(r5) |
85 | mr r1,r6 | 85 | mr r1,r5 |
86 | bl .handle_IRQ_event | 86 | bl .__do_IRQ |
87 | ld r1,0(r1) | 87 | ld r1,0(r1) |
88 | ld r0,16(r1) | 88 | ld r0,16(r1) |
89 | mtlr r0 | 89 | mtlr r0 |
diff --git a/arch/ppc64/kernel/nvram.c b/arch/ppc64/kernel/nvram.c index 4fb1a9f5060d..c0fcd29918ce 100644 --- a/arch/ppc64/kernel/nvram.c +++ b/arch/ppc64/kernel/nvram.c | |||
@@ -31,7 +31,6 @@ | |||
31 | #include <asm/rtas.h> | 31 | #include <asm/rtas.h> |
32 | #include <asm/prom.h> | 32 | #include <asm/prom.h> |
33 | #include <asm/machdep.h> | 33 | #include <asm/machdep.h> |
34 | #include <asm/systemcfg.h> | ||
35 | 34 | ||
36 | #undef DEBUG_NVRAM | 35 | #undef DEBUG_NVRAM |
37 | 36 | ||
@@ -167,7 +166,7 @@ static int dev_nvram_ioctl(struct inode *inode, struct file *file, | |||
167 | case IOC_NVRAM_GET_OFFSET: { | 166 | case IOC_NVRAM_GET_OFFSET: { |
168 | int part, offset; | 167 | int part, offset; |
169 | 168 | ||
170 | if (systemcfg->platform != PLATFORM_POWERMAC) | 169 | if (_machine != PLATFORM_POWERMAC) |
171 | return -EINVAL; | 170 | return -EINVAL; |
172 | if (copy_from_user(&part, (void __user*)arg, sizeof(part)) != 0) | 171 | if (copy_from_user(&part, (void __user*)arg, sizeof(part)) != 0) |
173 | return -EFAULT; | 172 | return -EFAULT; |
@@ -450,7 +449,7 @@ static int nvram_setup_partition(void) | |||
450 | * in our nvram, as Apple defined partitions use pretty much | 449 | * in our nvram, as Apple defined partitions use pretty much |
451 | * all of the space | 450 | * all of the space |
452 | */ | 451 | */ |
453 | if (systemcfg->platform == PLATFORM_POWERMAC) | 452 | if (_machine == PLATFORM_POWERMAC) |
454 | return -ENOSPC; | 453 | return -ENOSPC; |
455 | 454 | ||
456 | /* see if we have an OS partition that meets our needs. | 455 | /* see if we have an OS partition that meets our needs. |
diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c index 30247ff74972..3cef1b8f57f0 100644 --- a/arch/ppc64/kernel/pci.c +++ b/arch/ppc64/kernel/pci.c | |||
@@ -548,6 +548,11 @@ static int __init pcibios_init(void) | |||
548 | if (ppc64_isabridge_dev != NULL) | 548 | if (ppc64_isabridge_dev != NULL) |
549 | printk("ISA bridge at %s\n", pci_name(ppc64_isabridge_dev)); | 549 | printk("ISA bridge at %s\n", pci_name(ppc64_isabridge_dev)); |
550 | 550 | ||
551 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
552 | /* map in PCI I/O space */ | ||
553 | phbs_remap_io(); | ||
554 | #endif | ||
555 | |||
551 | printk("PCI: Probing PCI hardware done\n"); | 556 | printk("PCI: Probing PCI hardware done\n"); |
552 | 557 | ||
553 | return 0; | 558 | return 0; |
@@ -1277,12 +1282,9 @@ long sys_pciconfig_iobase(long which, unsigned long in_bus, | |||
1277 | * G5 machines... So when something asks for bus 0 io base | 1282 | * G5 machines... So when something asks for bus 0 io base |
1278 | * (bus 0 is HT root), we return the AGP one instead. | 1283 | * (bus 0 is HT root), we return the AGP one instead. |
1279 | */ | 1284 | */ |
1280 | #ifdef CONFIG_PPC_PMAC | 1285 | if (machine_is_compatible("MacRISC4")) |
1281 | if (systemcfg->platform == PLATFORM_POWERMAC && | ||
1282 | machine_is_compatible("MacRISC4")) | ||
1283 | if (in_bus == 0) | 1286 | if (in_bus == 0) |
1284 | in_bus = 0xf0; | 1287 | in_bus = 0xf0; |
1285 | #endif /* CONFIG_PPC_PMAC */ | ||
1286 | 1288 | ||
1287 | /* That syscall isn't quite compatible with PCI domains, but it's | 1289 | /* That syscall isn't quite compatible with PCI domains, but it's |
1288 | * used on pre-domains setup. We return the first match | 1290 | * used on pre-domains setup. We return the first match |
diff --git a/arch/ppc64/kernel/pci_dn.c b/arch/ppc64/kernel/pci_dn.c index 1a443a7ada4c..12c4c9e9bbc7 100644 --- a/arch/ppc64/kernel/pci_dn.c +++ b/arch/ppc64/kernel/pci_dn.c | |||
@@ -43,7 +43,7 @@ static void * __devinit update_dn_pci_info(struct device_node *dn, void *data) | |||
43 | u32 *regs; | 43 | u32 *regs; |
44 | struct pci_dn *pdn; | 44 | struct pci_dn *pdn; |
45 | 45 | ||
46 | if (phb->is_dynamic) | 46 | if (mem_init_done) |
47 | pdn = kmalloc(sizeof(*pdn), GFP_KERNEL); | 47 | pdn = kmalloc(sizeof(*pdn), GFP_KERNEL); |
48 | else | 48 | else |
49 | pdn = alloc_bootmem(sizeof(*pdn)); | 49 | pdn = alloc_bootmem(sizeof(*pdn)); |
@@ -120,6 +120,14 @@ void *traverse_pci_devices(struct device_node *start, traverse_func pre, | |||
120 | return NULL; | 120 | return NULL; |
121 | } | 121 | } |
122 | 122 | ||
123 | /** | ||
124 | * pci_devs_phb_init_dynamic - setup pci devices under this PHB | ||
125 | * phb: pci-to-host bridge (top-level bridge connecting to cpu) | ||
126 | * | ||
127 | * This routine is called both during boot, (before the memory | ||
128 | * subsystem is set up, before kmalloc is valid) and during the | ||
129 | * dynamic lpar operation of adding a PHB to a running system. | ||
130 | */ | ||
123 | void __devinit pci_devs_phb_init_dynamic(struct pci_controller *phb) | 131 | void __devinit pci_devs_phb_init_dynamic(struct pci_controller *phb) |
124 | { | 132 | { |
125 | struct device_node * dn = (struct device_node *) phb->arch_data; | 133 | struct device_node * dn = (struct device_node *) phb->arch_data; |
@@ -201,9 +209,14 @@ static struct notifier_block pci_dn_reconfig_nb = { | |||
201 | .notifier_call = pci_dn_reconfig_notifier, | 209 | .notifier_call = pci_dn_reconfig_notifier, |
202 | }; | 210 | }; |
203 | 211 | ||
204 | /* | 212 | /** |
205 | * Actually initialize the phbs. | 213 | * pci_devs_phb_init - Initialize phbs and pci devs under them. |
206 | * The buswalk on this phb has not happened yet. | 214 | * |
215 | * This routine walks over all phb's (pci-host bridges) on the | ||
216 | * system, and sets up assorted pci-related structures | ||
217 | * (including pci info in the device node structs) for each | ||
218 | * pci device found underneath. This routine runs once, | ||
219 | * early in the boot sequence. | ||
207 | */ | 220 | */ |
208 | void __init pci_devs_phb_init(void) | 221 | void __init pci_devs_phb_init(void) |
209 | { | 222 | { |
diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c index 3402fbee62c7..fbad2c360784 100644 --- a/arch/ppc64/kernel/prom.c +++ b/arch/ppc64/kernel/prom.c | |||
@@ -318,7 +318,7 @@ static int __devinit finish_node_interrupts(struct device_node *np, | |||
318 | } | 318 | } |
319 | 319 | ||
320 | /* We offset irq numbers for the u3 MPIC by 128 in PowerMac */ | 320 | /* We offset irq numbers for the u3 MPIC by 128 in PowerMac */ |
321 | if (systemcfg->platform == PLATFORM_POWERMAC && ic && ic->parent) { | 321 | if (_machine == PLATFORM_POWERMAC && ic && ic->parent) { |
322 | char *name = get_property(ic->parent, "name", NULL); | 322 | char *name = get_property(ic->parent, "name", NULL); |
323 | if (name && !strcmp(name, "u3")) | 323 | if (name && !strcmp(name, "u3")) |
324 | np->intrs[intrcount].line += 128; | 324 | np->intrs[intrcount].line += 128; |
@@ -1065,7 +1065,7 @@ static int __init early_init_dt_scan_chosen(unsigned long node, | |||
1065 | prop = (u32 *)of_get_flat_dt_prop(node, "linux,platform", NULL); | 1065 | prop = (u32 *)of_get_flat_dt_prop(node, "linux,platform", NULL); |
1066 | if (prop == NULL) | 1066 | if (prop == NULL) |
1067 | return 0; | 1067 | return 0; |
1068 | systemcfg->platform = *prop; | 1068 | _machine = *prop; |
1069 | 1069 | ||
1070 | /* check if iommu is forced on or off */ | 1070 | /* check if iommu is forced on or off */ |
1071 | if (of_get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL) | 1071 | if (of_get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL) |
@@ -1230,11 +1230,8 @@ void __init early_init_devtree(void *params) | |||
1230 | of_scan_flat_dt(early_init_dt_scan_memory, NULL); | 1230 | of_scan_flat_dt(early_init_dt_scan_memory, NULL); |
1231 | lmb_enforce_memory_limit(memory_limit); | 1231 | lmb_enforce_memory_limit(memory_limit); |
1232 | lmb_analyze(); | 1232 | lmb_analyze(); |
1233 | systemcfg->physicalMemorySize = lmb_phys_mem_size(); | ||
1234 | lmb_reserve(0, __pa(klimit)); | 1233 | lmb_reserve(0, __pa(klimit)); |
1235 | 1234 | ||
1236 | DBG("Phys. mem: %lx\n", systemcfg->physicalMemorySize); | ||
1237 | |||
1238 | /* Reserve LMB regions used by kernel, initrd, dt, etc... */ | 1235 | /* Reserve LMB regions used by kernel, initrd, dt, etc... */ |
1239 | early_reserve_mem(); | 1236 | early_reserve_mem(); |
1240 | 1237 | ||
@@ -1753,7 +1750,7 @@ static int of_finish_dynamic_node(struct device_node *node, | |||
1753 | /* We don't support that function on PowerMac, at least | 1750 | /* We don't support that function on PowerMac, at least |
1754 | * not yet | 1751 | * not yet |
1755 | */ | 1752 | */ |
1756 | if (systemcfg->platform == PLATFORM_POWERMAC) | 1753 | if (_machine == PLATFORM_POWERMAC) |
1757 | return -ENODEV; | 1754 | return -ENODEV; |
1758 | 1755 | ||
1759 | /* fix up new node's linux_phandle field */ | 1756 | /* fix up new node's linux_phandle field */ |
diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c index e4c880dab997..6375f40b23db 100644 --- a/arch/ppc64/kernel/prom_init.c +++ b/arch/ppc64/kernel/prom_init.c | |||
@@ -1934,7 +1934,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, unsigned long | |||
1934 | /* | 1934 | /* |
1935 | * On pSeries, inform the firmware about our capabilities | 1935 | * On pSeries, inform the firmware about our capabilities |
1936 | */ | 1936 | */ |
1937 | if (RELOC(of_platform) & PLATFORM_PSERIES) | 1937 | if (RELOC(of_platform) == PLATFORM_PSERIES || |
1938 | RELOC(of_platform) == PLATFORM_PSERIES_LPAR) | ||
1938 | prom_send_capabilities(); | 1939 | prom_send_capabilities(); |
1939 | 1940 | ||
1940 | /* | 1941 | /* |
diff --git a/arch/ppc64/kernel/vdso.c b/arch/ppc64/kernel/vdso.c index 4aacf521e3e4..1bbacac44988 100644 --- a/arch/ppc64/kernel/vdso.c +++ b/arch/ppc64/kernel/vdso.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <asm/machdep.h> | 34 | #include <asm/machdep.h> |
35 | #include <asm/cputable.h> | 35 | #include <asm/cputable.h> |
36 | #include <asm/sections.h> | 36 | #include <asm/sections.h> |
37 | #include <asm/systemcfg.h> | ||
37 | #include <asm/vdso.h> | 38 | #include <asm/vdso.h> |
38 | 39 | ||
39 | #undef DEBUG | 40 | #undef DEBUG |
@@ -179,7 +180,7 @@ static struct page * vdso_vma_nopage(struct vm_area_struct * vma, | |||
179 | * Last page is systemcfg. | 180 | * Last page is systemcfg. |
180 | */ | 181 | */ |
181 | if ((vma->vm_end - address) <= PAGE_SIZE) | 182 | if ((vma->vm_end - address) <= PAGE_SIZE) |
182 | pg = virt_to_page(systemcfg); | 183 | pg = virt_to_page(_systemcfg); |
183 | else | 184 | else |
184 | pg = virt_to_page(vbase + offset); | 185 | pg = virt_to_page(vbase + offset); |
185 | 186 | ||
@@ -604,7 +605,7 @@ void __init vdso_init(void) | |||
604 | get_page(pg); | 605 | get_page(pg); |
605 | } | 606 | } |
606 | 607 | ||
607 | get_page(virt_to_page(systemcfg)); | 608 | get_page(virt_to_page(_systemcfg)); |
608 | } | 609 | } |
609 | 610 | ||
610 | int in_gate_area_no_task(unsigned long addr) | 611 | int in_gate_area_no_task(unsigned long addr) |
diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c index 0cded0468003..821c81e8cd38 100644 --- a/drivers/atm/horizon.c +++ b/drivers/atm/horizon.c | |||
@@ -1511,8 +1511,8 @@ static inline short setup_idle_tx_channel (hrz_dev * dev, hrz_vcc * vcc) { | |||
1511 | // a.k.a. prepare the channel and remember that we have done so. | 1511 | // a.k.a. prepare the channel and remember that we have done so. |
1512 | 1512 | ||
1513 | tx_ch_desc * tx_desc = &memmap->tx_descs[tx_channel]; | 1513 | tx_ch_desc * tx_desc = &memmap->tx_descs[tx_channel]; |
1514 | u16 rd_ptr; | 1514 | u32 rd_ptr; |
1515 | u16 wr_ptr; | 1515 | u32 wr_ptr; |
1516 | u16 channel = vcc->channel; | 1516 | u16 channel = vcc->channel; |
1517 | 1517 | ||
1518 | unsigned long flags; | 1518 | unsigned long flags; |
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index 4d5ed18dad00..27bca34b4a65 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c | |||
@@ -147,7 +147,7 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) | |||
147 | printk(KERN_ERR PFX "unable to get memory for scratch page.\n"); | 147 | printk(KERN_ERR PFX "unable to get memory for scratch page.\n"); |
148 | return -ENOMEM; | 148 | return -ENOMEM; |
149 | } | 149 | } |
150 | global_flush_tlb(); | 150 | flush_agp_mappings(); |
151 | 151 | ||
152 | bridge->scratch_page_real = virt_to_gart(addr); | 152 | bridge->scratch_page_real = virt_to_gart(addr); |
153 | bridge->scratch_page = | 153 | bridge->scratch_page = |
@@ -191,7 +191,7 @@ err_out: | |||
191 | if (bridge->driver->needs_scratch_page) { | 191 | if (bridge->driver->needs_scratch_page) { |
192 | bridge->driver->agp_destroy_page( | 192 | bridge->driver->agp_destroy_page( |
193 | gart_to_virt(bridge->scratch_page_real)); | 193 | gart_to_virt(bridge->scratch_page_real)); |
194 | global_flush_tlb(); | 194 | flush_agp_mappings(); |
195 | } | 195 | } |
196 | if (got_gatt) | 196 | if (got_gatt) |
197 | bridge->driver->free_gatt_table(bridge); | 197 | bridge->driver->free_gatt_table(bridge); |
@@ -217,7 +217,7 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge) | |||
217 | bridge->driver->needs_scratch_page) { | 217 | bridge->driver->needs_scratch_page) { |
218 | bridge->driver->agp_destroy_page( | 218 | bridge->driver->agp_destroy_page( |
219 | gart_to_virt(bridge->scratch_page_real)); | 219 | gart_to_virt(bridge->scratch_page_real)); |
220 | global_flush_tlb(); | 220 | flush_agp_mappings(); |
221 | } | 221 | } |
222 | } | 222 | } |
223 | 223 | ||
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 19f242b50781..5567ce8d72b0 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c | |||
@@ -155,7 +155,7 @@ void agp_free_memory(struct agp_memory *curr) | |||
155 | for (i = 0; i < curr->page_count; i++) { | 155 | for (i = 0; i < curr->page_count; i++) { |
156 | curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i])); | 156 | curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i])); |
157 | } | 157 | } |
158 | global_flush_tlb(); | 158 | flush_agp_mappings(); |
159 | } | 159 | } |
160 | agp_free_key(curr->key); | 160 | agp_free_key(curr->key); |
161 | vfree(curr->memory); | 161 | vfree(curr->memory); |
@@ -213,8 +213,6 @@ struct agp_memory *agp_allocate_memory(struct agp_bridge_data *bridge, | |||
213 | new->memory[i] = virt_to_gart(addr); | 213 | new->memory[i] = virt_to_gart(addr); |
214 | new->page_count++; | 214 | new->page_count++; |
215 | } | 215 | } |
216 | global_flush_tlb(); | ||
217 | |||
218 | new->bridge = bridge; | 216 | new->bridge = bridge; |
219 | 217 | ||
220 | flush_agp_mappings(); | 218 | flush_agp_mappings(); |
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 70ef926c3bd8..4e9a04e1f08e 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c | |||
@@ -180,11 +180,10 @@ superio_exit(void) | |||
180 | #define W83781D_REG_BANK 0x4E | 180 | #define W83781D_REG_BANK 0x4E |
181 | 181 | ||
182 | #define W83781D_REG_CONFIG 0x40 | 182 | #define W83781D_REG_CONFIG 0x40 |
183 | #define W83781D_REG_ALARM1 0x41 | 183 | #define W83781D_REG_ALARM1 0x459 |
184 | #define W83781D_REG_ALARM2 0x42 | 184 | #define W83781D_REG_ALARM2 0x45A |
185 | #define W83781D_REG_ALARM3 0x450 | 185 | #define W83781D_REG_ALARM3 0x45B |
186 | 186 | ||
187 | #define W83781D_REG_IRQ 0x4C | ||
188 | #define W83781D_REG_BEEP_CONFIG 0x4D | 187 | #define W83781D_REG_BEEP_CONFIG 0x4D |
189 | #define W83781D_REG_BEEP_INTS1 0x56 | 188 | #define W83781D_REG_BEEP_INTS1 0x56 |
190 | #define W83781D_REG_BEEP_INTS2 0x57 | 189 | #define W83781D_REG_BEEP_INTS2 0x57 |
@@ -1370,13 +1369,6 @@ static void w83627hf_init_client(struct i2c_client *client) | |||
1370 | W83781D_REG_TEMP3_CONFIG, tmp & 0xfe); | 1369 | W83781D_REG_TEMP3_CONFIG, tmp & 0xfe); |
1371 | } | 1370 | } |
1372 | } | 1371 | } |
1373 | |||
1374 | /* enable comparator mode for temp2 and temp3 so | ||
1375 | alarm indication will work correctly */ | ||
1376 | i = w83627hf_read_value(client, W83781D_REG_IRQ); | ||
1377 | if (!(i & 0x40)) | ||
1378 | w83627hf_write_value(client, W83781D_REG_IRQ, | ||
1379 | i | 0x40); | ||
1380 | } | 1372 | } |
1381 | 1373 | ||
1382 | /* Start monitoring */ | 1374 | /* Start monitoring */ |
@@ -1400,7 +1392,7 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev) | |||
1400 | /* skip missing sensors */ | 1392 | /* skip missing sensors */ |
1401 | if (((data->type == w83697hf) && (i == 1)) || | 1393 | if (((data->type == w83697hf) && (i == 1)) || |
1402 | ((data->type == w83627thf || data->type == w83637hf) | 1394 | ((data->type == w83627thf || data->type == w83637hf) |
1403 | && (i == 4 || i == 5))) | 1395 | && (i == 5 || i == 6))) |
1404 | continue; | 1396 | continue; |
1405 | data->in[i] = | 1397 | data->in[i] = |
1406 | w83627hf_read_value(client, W83781D_REG_IN(i)); | 1398 | w83627hf_read_value(client, W83781D_REG_IN(i)); |
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index c9366b504833..a2237d4b2cf2 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c | |||
@@ -142,19 +142,18 @@ static int vt596_transaction(u8 size) | |||
142 | /* Make sure the SMBus host is ready to start transmitting */ | 142 | /* Make sure the SMBus host is ready to start transmitting */ |
143 | if ((temp = inb_p(SMBHSTSTS)) & 0x1F) { | 143 | if ((temp = inb_p(SMBHSTSTS)) & 0x1F) { |
144 | dev_dbg(&vt596_adapter.dev, "SMBus busy (0x%02x). " | 144 | dev_dbg(&vt596_adapter.dev, "SMBus busy (0x%02x). " |
145 | "Resetting... ", temp); | 145 | "Resetting...\n", temp); |
146 | 146 | ||
147 | outb_p(temp, SMBHSTSTS); | 147 | outb_p(temp, SMBHSTSTS); |
148 | if ((temp = inb_p(SMBHSTSTS)) & 0x1F) { | 148 | if ((temp = inb_p(SMBHSTSTS)) & 0x1F) { |
149 | printk("Failed! (0x%02x)\n", temp); | 149 | dev_err(&vt596_adapter.dev, "SMBus reset failed! " |
150 | "(0x%02x)\n", temp); | ||
150 | return -1; | 151 | return -1; |
151 | } else { | ||
152 | printk("Successful!\n"); | ||
153 | } | 152 | } |
154 | } | 153 | } |
155 | 154 | ||
156 | /* Start the transaction by setting bit 6 */ | 155 | /* Start the transaction by setting bit 6 */ |
157 | outb_p(0x40 | (size & 0x3C), SMBHSTCNT); | 156 | outb_p(0x40 | size, SMBHSTCNT); |
158 | 157 | ||
159 | /* We will always wait for a fraction of a second */ | 158 | /* We will always wait for a fraction of a second */ |
160 | do { | 159 | do { |
@@ -171,7 +170,7 @@ static int vt596_transaction(u8 size) | |||
171 | if (temp & 0x10) { | 170 | if (temp & 0x10) { |
172 | result = -1; | 171 | result = -1; |
173 | dev_err(&vt596_adapter.dev, "Transaction failed (0x%02x)\n", | 172 | dev_err(&vt596_adapter.dev, "Transaction failed (0x%02x)\n", |
174 | inb_p(SMBHSTCNT) & 0x3C); | 173 | size); |
175 | } | 174 | } |
176 | 175 | ||
177 | if (temp & 0x08) { | 176 | if (temp & 0x08) { |
@@ -180,11 +179,13 @@ static int vt596_transaction(u8 size) | |||
180 | } | 179 | } |
181 | 180 | ||
182 | if (temp & 0x04) { | 181 | if (temp & 0x04) { |
182 | int read = inb_p(SMBHSTADD) & 0x01; | ||
183 | result = -1; | 183 | result = -1; |
184 | /* Quick commands are used to probe for chips, so | 184 | /* The quick and receive byte commands are used to probe |
185 | errors are expected, and we don't want to frighten the | 185 | for chips, so errors are expected, and we don't want |
186 | user. */ | 186 | to frighten the user. */ |
187 | if ((inb_p(SMBHSTCNT) & 0x3C) != VT596_QUICK) | 187 | if (!((size == VT596_QUICK && !read) || |
188 | (size == VT596_BYTE && read))) | ||
188 | dev_err(&vt596_adapter.dev, "Transaction error!\n"); | 189 | dev_err(&vt596_adapter.dev, "Transaction error!\n"); |
189 | } | 190 | } |
190 | 191 | ||
@@ -462,9 +463,9 @@ static void __exit i2c_vt596_exit(void) | |||
462 | } | 463 | } |
463 | } | 464 | } |
464 | 465 | ||
465 | MODULE_AUTHOR( | 466 | MODULE_AUTHOR("Kyosti Malkki <kmalkki@cc.hut.fi>, " |
466 | "Frodo Looijaard <frodol@dds.nl> and " | 467 | "Mark D. Studebaker <mdsxyz123@yahoo.com> and " |
467 | "Philip Edelbrock <phil@netroedge.com>"); | 468 | "Jean Delvare <khali@linux-fr.org>"); |
468 | MODULE_DESCRIPTION("vt82c596 SMBus driver"); | 469 | MODULE_DESCRIPTION("vt82c596 SMBus driver"); |
469 | MODULE_LICENSE("GPL"); | 470 | MODULE_LICENSE("GPL"); |
470 | 471 | ||
diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c index 01b037007410..02682fb794c8 100644 --- a/drivers/i2c/chips/ds1337.c +++ b/drivers/i2c/chips/ds1337.c | |||
@@ -164,9 +164,9 @@ static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt) | |||
164 | buf[1] = BIN2BCD(dt->tm_sec); | 164 | buf[1] = BIN2BCD(dt->tm_sec); |
165 | buf[2] = BIN2BCD(dt->tm_min); | 165 | buf[2] = BIN2BCD(dt->tm_min); |
166 | buf[3] = BIN2BCD(dt->tm_hour); | 166 | buf[3] = BIN2BCD(dt->tm_hour); |
167 | buf[4] = BIN2BCD(dt->tm_wday) + 1; | 167 | buf[4] = BIN2BCD(dt->tm_wday + 1); |
168 | buf[5] = BIN2BCD(dt->tm_mday); | 168 | buf[5] = BIN2BCD(dt->tm_mday); |
169 | buf[6] = BIN2BCD(dt->tm_mon) + 1; | 169 | buf[6] = BIN2BCD(dt->tm_mon + 1); |
170 | val = dt->tm_year; | 170 | val = dt->tm_year; |
171 | if (val >= 100) { | 171 | if (val >= 100) { |
172 | val -= 100; | 172 | val -= 100; |
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index a737886e39d1..42e5b8175cbf 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig | |||
@@ -539,6 +539,15 @@ config BLK_DEV_CS5530 | |||
539 | 539 | ||
540 | It is safe to say Y to this question. | 540 | It is safe to say Y to this question. |
541 | 541 | ||
542 | config BLK_DEV_CS5535 | ||
543 | tristate "AMD CS5535 chipset support" | ||
544 | depends on X86 && !X86_64 | ||
545 | help | ||
546 | Include support for UDMA on the NSC/AMD CS5535 companion chipset. | ||
547 | This will automatically be detected and configured if found. | ||
548 | |||
549 | It is safe to say Y to this question. | ||
550 | |||
542 | config BLK_DEV_HPT34X | 551 | config BLK_DEV_HPT34X |
543 | tristate "HPT34X chipset support" | 552 | tristate "HPT34X chipset support" |
544 | help | 553 | help |
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index e83f54d37f96..f615ab759962 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c | |||
@@ -2038,11 +2038,9 @@ static int idefloppy_ioctl(struct inode *inode, struct file *file, | |||
2038 | struct ide_floppy_obj *floppy = ide_floppy_g(bdev->bd_disk); | 2038 | struct ide_floppy_obj *floppy = ide_floppy_g(bdev->bd_disk); |
2039 | ide_drive_t *drive = floppy->drive; | 2039 | ide_drive_t *drive = floppy->drive; |
2040 | void __user *argp = (void __user *)arg; | 2040 | void __user *argp = (void __user *)arg; |
2041 | int err = generic_ide_ioctl(drive, file, bdev, cmd, arg); | 2041 | int err; |
2042 | int prevent = (arg) ? 1 : 0; | 2042 | int prevent = (arg) ? 1 : 0; |
2043 | idefloppy_pc_t pc; | 2043 | idefloppy_pc_t pc; |
2044 | if (err != -EINVAL) | ||
2045 | return err; | ||
2046 | 2044 | ||
2047 | switch (cmd) { | 2045 | switch (cmd) { |
2048 | case CDROMEJECT: | 2046 | case CDROMEJECT: |
@@ -2094,7 +2092,7 @@ static int idefloppy_ioctl(struct inode *inode, struct file *file, | |||
2094 | case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS: | 2092 | case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS: |
2095 | return idefloppy_get_format_progress(drive, argp); | 2093 | return idefloppy_get_format_progress(drive, argp); |
2096 | } | 2094 | } |
2097 | return -EINVAL; | 2095 | return generic_ide_ioctl(drive, file, bdev, cmd, arg); |
2098 | } | 2096 | } |
2099 | 2097 | ||
2100 | static int idefloppy_media_changed(struct gendisk *disk) | 2098 | static int idefloppy_media_changed(struct gendisk *disk) |
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index 0b0aa4f51628..af7af958ab3e 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c | |||
@@ -104,8 +104,6 @@ void default_hwif_iops (ide_hwif_t *hwif) | |||
104 | hwif->INSL = ide_insl; | 104 | hwif->INSL = ide_insl; |
105 | } | 105 | } |
106 | 106 | ||
107 | EXPORT_SYMBOL(default_hwif_iops); | ||
108 | |||
109 | /* | 107 | /* |
110 | * MMIO operations, typically used for SATA controllers | 108 | * MMIO operations, typically used for SATA controllers |
111 | */ | 109 | */ |
@@ -329,8 +327,6 @@ void default_hwif_transport(ide_hwif_t *hwif) | |||
329 | hwif->atapi_output_bytes = atapi_output_bytes; | 327 | hwif->atapi_output_bytes = atapi_output_bytes; |
330 | } | 328 | } |
331 | 329 | ||
332 | EXPORT_SYMBOL(default_hwif_transport); | ||
333 | |||
334 | /* | 330 | /* |
335 | * Beginning of Taskfile OPCODE Library and feature sets. | 331 | * Beginning of Taskfile OPCODE Library and feature sets. |
336 | */ | 332 | */ |
@@ -529,8 +525,6 @@ int wait_for_ready (ide_drive_t *drive, int timeout) | |||
529 | return 0; | 525 | return 0; |
530 | } | 526 | } |
531 | 527 | ||
532 | EXPORT_SYMBOL(wait_for_ready); | ||
533 | |||
534 | /* | 528 | /* |
535 | * This routine busy-waits for the drive status to be not "busy". | 529 | * This routine busy-waits for the drive status to be not "busy". |
536 | * It then checks the status for all of the "good" bits and none | 530 | * It then checks the status for all of the "good" bits and none |
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 7ec18fa3b5ff..54f9639c2a8c 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c | |||
@@ -161,8 +161,6 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task) | |||
161 | return ide_stopped; | 161 | return ide_stopped; |
162 | } | 162 | } |
163 | 163 | ||
164 | EXPORT_SYMBOL(do_rw_taskfile); | ||
165 | |||
166 | /* | 164 | /* |
167 | * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd. | 165 | * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd. |
168 | */ | 166 | */ |
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 9fe19808d815..8af179b531c3 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c | |||
@@ -803,6 +803,7 @@ found: | |||
803 | hwif->irq = hw->irq; | 803 | hwif->irq = hw->irq; |
804 | hwif->noprobe = 0; | 804 | hwif->noprobe = 0; |
805 | hwif->chipset = hw->chipset; | 805 | hwif->chipset = hw->chipset; |
806 | hwif->gendev.parent = hw->dev; | ||
806 | 807 | ||
807 | if (!initializing) { | 808 | if (!initializing) { |
808 | probe_hwif_init_with_fixup(hwif, fixup); | 809 | probe_hwif_init_with_fixup(hwif, fixup); |
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index 1dafffa7e513..ef79805218e4 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c | |||
@@ -182,13 +182,14 @@ static void ide_detach(dev_link_t *link) | |||
182 | 182 | ||
183 | } /* ide_detach */ | 183 | } /* ide_detach */ |
184 | 184 | ||
185 | static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq) | 185 | static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq, struct pcmcia_device *handle) |
186 | { | 186 | { |
187 | hw_regs_t hw; | 187 | hw_regs_t hw; |
188 | memset(&hw, 0, sizeof(hw)); | 188 | memset(&hw, 0, sizeof(hw)); |
189 | ide_init_hwif_ports(&hw, io, ctl, NULL); | 189 | ide_init_hwif_ports(&hw, io, ctl, NULL); |
190 | hw.irq = irq; | 190 | hw.irq = irq; |
191 | hw.chipset = ide_pci; | 191 | hw.chipset = ide_pci; |
192 | hw.dev = &handle->dev; | ||
192 | return ide_register_hw_with_fixup(&hw, NULL, ide_undecoded_slave); | 193 | return ide_register_hw_with_fixup(&hw, NULL, ide_undecoded_slave); |
193 | } | 194 | } |
194 | 195 | ||
@@ -327,12 +328,12 @@ static void ide_config(dev_link_t *link) | |||
327 | 328 | ||
328 | /* retry registration in case device is still spinning up */ | 329 | /* retry registration in case device is still spinning up */ |
329 | for (hd = -1, i = 0; i < 10; i++) { | 330 | for (hd = -1, i = 0; i < 10; i++) { |
330 | hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ); | 331 | hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, handle); |
331 | if (hd >= 0) break; | 332 | if (hd >= 0) break; |
332 | if (link->io.NumPorts1 == 0x20) { | 333 | if (link->io.NumPorts1 == 0x20) { |
333 | outb(0x02, ctl_base + 0x10); | 334 | outb(0x02, ctl_base + 0x10); |
334 | hd = idecs_register(io_base + 0x10, ctl_base + 0x10, | 335 | hd = idecs_register(io_base + 0x10, ctl_base + 0x10, |
335 | link->irq.AssignedIRQ); | 336 | link->irq.AssignedIRQ, handle); |
336 | if (hd >= 0) { | 337 | if (hd >= 0) { |
337 | io_base += 0x10; | 338 | io_base += 0x10; |
338 | ctl_base += 0x10; | 339 | ctl_base += 0x10; |
diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile index af46226c1796..f35d684edc25 100644 --- a/drivers/ide/pci/Makefile +++ b/drivers/ide/pci/Makefile | |||
@@ -6,6 +6,7 @@ obj-$(CONFIG_BLK_DEV_ATIIXP) += atiixp.o | |||
6 | obj-$(CONFIG_BLK_DEV_CMD64X) += cmd64x.o | 6 | obj-$(CONFIG_BLK_DEV_CMD64X) += cmd64x.o |
7 | obj-$(CONFIG_BLK_DEV_CS5520) += cs5520.o | 7 | obj-$(CONFIG_BLK_DEV_CS5520) += cs5520.o |
8 | obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o | 8 | obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o |
9 | obj-$(CONFIG_BLK_DEV_CS5535) += cs5535.o | ||
9 | obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o | 10 | obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o |
10 | obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o | 11 | obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o |
11 | obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o | 12 | obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o |
diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index 844a6c9fb949..21965e5ef25e 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c | |||
@@ -74,6 +74,7 @@ static struct amd_ide_chip { | |||
74 | { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, 0x50, AMD_UDMA_133 }, | 74 | { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, 0x50, AMD_UDMA_133 }, |
75 | { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, 0x50, AMD_UDMA_133 }, | 75 | { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, 0x50, AMD_UDMA_133 }, |
76 | { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, 0x50, AMD_UDMA_133 }, | 76 | { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, 0x50, AMD_UDMA_133 }, |
77 | { PCI_DEVICE_ID_AMD_CS5536_IDE, 0x40, AMD_UDMA_100 }, | ||
77 | { 0 } | 78 | { 0 } |
78 | }; | 79 | }; |
79 | 80 | ||
@@ -491,6 +492,7 @@ static ide_pci_device_t amd74xx_chipsets[] __devinitdata = { | |||
491 | /* 14 */ DECLARE_NV_DEV("NFORCE-MCP04"), | 492 | /* 14 */ DECLARE_NV_DEV("NFORCE-MCP04"), |
492 | /* 15 */ DECLARE_NV_DEV("NFORCE-MCP51"), | 493 | /* 15 */ DECLARE_NV_DEV("NFORCE-MCP51"), |
493 | /* 16 */ DECLARE_NV_DEV("NFORCE-MCP55"), | 494 | /* 16 */ DECLARE_NV_DEV("NFORCE-MCP55"), |
495 | /* 17 */ DECLARE_AMD_DEV("AMD5536"), | ||
494 | }; | 496 | }; |
495 | 497 | ||
496 | static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id) | 498 | static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id) |
@@ -527,6 +529,7 @@ static struct pci_device_id amd74xx_pci_tbl[] = { | |||
527 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 }, | 529 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 }, |
528 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 }, | 530 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 }, |
529 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16 }, | 531 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16 }, |
532 | { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17 }, | ||
530 | { 0, }, | 533 | { 0, }, |
531 | }; | 534 | }; |
532 | MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl); | 535 | MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl); |
diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c new file mode 100644 index 000000000000..6eb305197f3c --- /dev/null +++ b/drivers/ide/pci/cs5535.c | |||
@@ -0,0 +1,305 @@ | |||
1 | /* | ||
2 | * linux/drivers/ide/pci/cs5535.c | ||
3 | * | ||
4 | * Copyright (C) 2004-2005 Advanced Micro Devices, Inc. | ||
5 | * | ||
6 | * History: | ||
7 | * 09/20/2005 - Jaya Kumar <jayakumar.ide@gmail.com> | ||
8 | * - Reworked tuneproc, set_drive, misc mods to prep for mainline | ||
9 | * - Work was sponsored by CIS (M) Sdn Bhd. | ||
10 | * Ported to Kernel 2.6.11 on June 26, 2005 by | ||
11 | * Wolfgang Zuleger <wolfgang.zuleger@gmx.de> | ||
12 | * Alexander Kiausch <alex.kiausch@t-online.de> | ||
13 | * Originally developed by AMD for 2.4/2.6 | ||
14 | * | ||
15 | * Development of this chipset driver was funded | ||
16 | * by the nice folks at National Semiconductor/AMD. | ||
17 | * | ||
18 | * This program is free software; you can redistribute it and/or modify it | ||
19 | * under the terms of the GNU General Public License version 2 as published by | ||
20 | * the Free Software Foundation. | ||
21 | * | ||
22 | * Documentation: | ||
23 | * CS5535 documentation available from AMD | ||
24 | */ | ||
25 | |||
26 | #include <linux/config.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/pci.h> | ||
29 | #include <linux/ide.h> | ||
30 | |||
31 | #include "ide-timing.h" | ||
32 | |||
33 | #define MSR_ATAC_BASE 0x51300000 | ||
34 | #define ATAC_GLD_MSR_CAP (MSR_ATAC_BASE+0) | ||
35 | #define ATAC_GLD_MSR_CONFIG (MSR_ATAC_BASE+0x01) | ||
36 | #define ATAC_GLD_MSR_SMI (MSR_ATAC_BASE+0x02) | ||
37 | #define ATAC_GLD_MSR_ERROR (MSR_ATAC_BASE+0x03) | ||
38 | #define ATAC_GLD_MSR_PM (MSR_ATAC_BASE+0x04) | ||
39 | #define ATAC_GLD_MSR_DIAG (MSR_ATAC_BASE+0x05) | ||
40 | #define ATAC_IO_BAR (MSR_ATAC_BASE+0x08) | ||
41 | #define ATAC_RESET (MSR_ATAC_BASE+0x10) | ||
42 | #define ATAC_CH0D0_PIO (MSR_ATAC_BASE+0x20) | ||
43 | #define ATAC_CH0D0_DMA (MSR_ATAC_BASE+0x21) | ||
44 | #define ATAC_CH0D1_PIO (MSR_ATAC_BASE+0x22) | ||
45 | #define ATAC_CH0D1_DMA (MSR_ATAC_BASE+0x23) | ||
46 | #define ATAC_PCI_ABRTERR (MSR_ATAC_BASE+0x24) | ||
47 | #define ATAC_BM0_CMD_PRIM 0x00 | ||
48 | #define ATAC_BM0_STS_PRIM 0x02 | ||
49 | #define ATAC_BM0_PRD 0x04 | ||
50 | #define CS5535_CABLE_DETECT 0x48 | ||
51 | |||
52 | /* Format I PIO settings. We seperate out cmd and data for safer timings */ | ||
53 | |||
54 | static unsigned int cs5535_pio_cmd_timings[5] = | ||
55 | { 0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131 }; | ||
56 | static unsigned int cs5535_pio_dta_timings[5] = | ||
57 | { 0xF7F4, 0xF173, 0x8141, 0x5131, 0x1131 }; | ||
58 | |||
59 | static unsigned int cs5535_mwdma_timings[3] = | ||
60 | { 0x7F0FFFF3, 0x7F035352, 0x7f024241 }; | ||
61 | |||
62 | static unsigned int cs5535_udma_timings[5] = | ||
63 | { 0x7F7436A1, 0x7F733481, 0x7F723261, 0x7F713161, 0x7F703061 }; | ||
64 | |||
65 | /* Macros to check if the register is the reset value - reset value is an | ||
66 | invalid timing and indicates the register has not been set previously */ | ||
67 | |||
68 | #define CS5535_BAD_PIO(timings) ( (timings&~0x80000000UL) == 0x00009172 ) | ||
69 | #define CS5535_BAD_DMA(timings) ( (timings & 0x000FFFFF) == 0x00077771 ) | ||
70 | |||
71 | /**** | ||
72 | * cs5535_set_speed - Configure the chipset to the new speed | ||
73 | * @drive: Drive to set up | ||
74 | * @speed: desired speed | ||
75 | * | ||
76 | * cs5535_set_speed() configures the chipset to a new speed. | ||
77 | */ | ||
78 | static void cs5535_set_speed(ide_drive_t *drive, u8 speed) | ||
79 | { | ||
80 | |||
81 | u32 reg = 0, dummy; | ||
82 | int unit = drive->select.b.unit; | ||
83 | |||
84 | |||
85 | /* Set the PIO timings */ | ||
86 | if ((speed & XFER_MODE) == XFER_PIO) { | ||
87 | u8 pioa; | ||
88 | u8 piob; | ||
89 | u8 cmd; | ||
90 | |||
91 | pioa = speed - XFER_PIO_0; | ||
92 | piob = ide_get_best_pio_mode(&(drive->hwif->drives[!unit]), | ||
93 | 255, 4, NULL); | ||
94 | cmd = pioa < piob ? pioa : piob; | ||
95 | |||
96 | /* Write the speed of the current drive */ | ||
97 | reg = (cs5535_pio_cmd_timings[cmd] << 16) | | ||
98 | cs5535_pio_dta_timings[pioa]; | ||
99 | wrmsr(unit ? ATAC_CH0D1_PIO : ATAC_CH0D0_PIO, reg, 0); | ||
100 | |||
101 | /* And if nessesary - change the speed of the other drive */ | ||
102 | rdmsr(unit ? ATAC_CH0D0_PIO : ATAC_CH0D1_PIO, reg, dummy); | ||
103 | |||
104 | if (((reg >> 16) & cs5535_pio_cmd_timings[cmd]) != | ||
105 | cs5535_pio_cmd_timings[cmd]) { | ||
106 | reg &= 0x0000FFFF; | ||
107 | reg |= cs5535_pio_cmd_timings[cmd] << 16; | ||
108 | wrmsr(unit ? ATAC_CH0D0_PIO : ATAC_CH0D1_PIO, reg, 0); | ||
109 | } | ||
110 | |||
111 | /* Set bit 31 of the DMA register for PIO format 1 timings */ | ||
112 | rdmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, dummy); | ||
113 | wrmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, | ||
114 | reg | 0x80000000UL, 0); | ||
115 | } else { | ||
116 | rdmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, dummy); | ||
117 | |||
118 | reg &= 0x80000000UL; /* Preserve the PIO format bit */ | ||
119 | |||
120 | if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_7) | ||
121 | reg |= cs5535_udma_timings[speed - XFER_UDMA_0]; | ||
122 | else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) | ||
123 | reg |= cs5535_mwdma_timings[speed - XFER_MW_DMA_0]; | ||
124 | else | ||
125 | return; | ||
126 | |||
127 | wrmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, 0); | ||
128 | } | ||
129 | } | ||
130 | |||
131 | static u8 cs5535_ratemask(ide_drive_t *drive) | ||
132 | { | ||
133 | /* eighty93 will return 1 if it's 80core and capable of | ||
134 | exceeding udma2, 0 otherwise. we need ratemask to set | ||
135 | the max speed and if we can > udma2 then we return 2 | ||
136 | which selects speed_max as udma4 which is the 5535's max | ||
137 | speed, and 1 selects udma2 which is the max for 40c */ | ||
138 | if (!eighty_ninty_three(drive)) | ||
139 | return 1; | ||
140 | |||
141 | return 2; | ||
142 | } | ||
143 | |||
144 | |||
145 | /**** | ||
146 | * cs5535_set_drive - Configure the drive to the new speed | ||
147 | * @drive: Drive to set up | ||
148 | * @speed: desired speed | ||
149 | * | ||
150 | * cs5535_set_drive() configures the drive and the chipset to a | ||
151 | * new speed. It also can be called by upper layers. | ||
152 | */ | ||
153 | static int cs5535_set_drive(ide_drive_t *drive, u8 speed) | ||
154 | { | ||
155 | speed = ide_rate_filter(cs5535_ratemask(drive), speed); | ||
156 | ide_config_drive_speed(drive, speed); | ||
157 | cs5535_set_speed(drive, speed); | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | /**** | ||
163 | * cs5535_tuneproc - PIO setup | ||
164 | * @drive: drive to set up | ||
165 | * @pio: mode to use (255 for 'best possible') | ||
166 | * | ||
167 | * A callback from the upper layers for PIO-only tuning. | ||
168 | */ | ||
169 | static void cs5535_tuneproc(ide_drive_t *drive, u8 xferspeed) | ||
170 | { | ||
171 | u8 modes[] = { XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, | ||
172 | XFER_PIO_4 }; | ||
173 | |||
174 | /* cs5535 max pio is pio 4, best_pio will check the blacklist. | ||
175 | i think we don't need to rate_filter the incoming xferspeed | ||
176 | since we know we're only going to choose pio */ | ||
177 | xferspeed = ide_get_best_pio_mode(drive, xferspeed, 4, NULL); | ||
178 | ide_config_drive_speed(drive, modes[xferspeed]); | ||
179 | cs5535_set_speed(drive, xferspeed); | ||
180 | } | ||
181 | |||
182 | static int cs5535_config_drive_for_dma(ide_drive_t *drive) | ||
183 | { | ||
184 | u8 speed; | ||
185 | |||
186 | speed = ide_dma_speed(drive, cs5535_ratemask(drive)); | ||
187 | |||
188 | /* If no DMA speed was available then let dma_check hit pio */ | ||
189 | if (!speed) { | ||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | cs5535_set_drive(drive, speed); | ||
194 | return ide_dma_enable(drive); | ||
195 | } | ||
196 | |||
197 | static int cs5535_dma_check(ide_drive_t *drive) | ||
198 | { | ||
199 | ide_hwif_t *hwif = drive->hwif; | ||
200 | struct hd_driveid *id = drive->id; | ||
201 | u8 speed; | ||
202 | |||
203 | drive->init_speed = 0; | ||
204 | |||
205 | if ((id->capability & 1) && drive->autodma) { | ||
206 | if (ide_use_dma(drive)) { | ||
207 | if (cs5535_config_drive_for_dma(drive)) | ||
208 | return hwif->ide_dma_on(drive); | ||
209 | } | ||
210 | |||
211 | goto fast_ata_pio; | ||
212 | |||
213 | } else if ((id->capability & 8) || (id->field_valid & 2)) { | ||
214 | fast_ata_pio: | ||
215 | speed = ide_get_best_pio_mode(drive, 255, 4, NULL); | ||
216 | cs5535_set_drive(drive, speed); | ||
217 | return hwif->ide_dma_off_quietly(drive); | ||
218 | } | ||
219 | /* IORDY not supported */ | ||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | static u8 __devinit cs5535_cable_detect(struct pci_dev *dev) | ||
224 | { | ||
225 | u8 bit; | ||
226 | |||
227 | /* if a 80 wire cable was detected */ | ||
228 | pci_read_config_byte(dev, CS5535_CABLE_DETECT, &bit); | ||
229 | return (bit & 1); | ||
230 | } | ||
231 | |||
232 | /**** | ||
233 | * init_hwif_cs5535 - Initialize one ide cannel | ||
234 | * @hwif: Channel descriptor | ||
235 | * | ||
236 | * This gets invoked by the IDE driver once for each channel. It | ||
237 | * performs channel-specific pre-initialization before drive probing. | ||
238 | * | ||
239 | */ | ||
240 | static void __devinit init_hwif_cs5535(ide_hwif_t *hwif) | ||
241 | { | ||
242 | int i; | ||
243 | |||
244 | hwif->autodma = 0; | ||
245 | |||
246 | hwif->tuneproc = &cs5535_tuneproc; | ||
247 | hwif->speedproc = &cs5535_set_drive; | ||
248 | hwif->ide_dma_check = &cs5535_dma_check; | ||
249 | |||
250 | hwif->atapi_dma = 1; | ||
251 | hwif->ultra_mask = 0x1F; | ||
252 | hwif->mwdma_mask = 0x07; | ||
253 | |||
254 | |||
255 | hwif->udma_four = cs5535_cable_detect(hwif->pci_dev); | ||
256 | |||
257 | if (!noautodma) | ||
258 | hwif->autodma = 1; | ||
259 | |||
260 | /* just setting autotune and not worrying about bios timings */ | ||
261 | for (i = 0; i < 2; i++) { | ||
262 | hwif->drives[i].autotune = 1; | ||
263 | hwif->drives[i].autodma = hwif->autodma; | ||
264 | } | ||
265 | } | ||
266 | |||
267 | static ide_pci_device_t cs5535_chipset __devinitdata = { | ||
268 | .name = "CS5535", | ||
269 | .init_hwif = init_hwif_cs5535, | ||
270 | .channels = 1, | ||
271 | .autodma = AUTODMA, | ||
272 | .bootable = ON_BOARD, | ||
273 | }; | ||
274 | |||
275 | static int __devinit cs5535_init_one(struct pci_dev *dev, | ||
276 | const struct pci_device_id *id) | ||
277 | { | ||
278 | return ide_setup_pci_device(dev, &cs5535_chipset); | ||
279 | } | ||
280 | |||
281 | static struct pci_device_id cs5535_pci_tbl[] = | ||
282 | { | ||
283 | { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_IDE, PCI_ANY_ID, | ||
284 | PCI_ANY_ID, 0, 0, 0}, | ||
285 | { 0, }, | ||
286 | }; | ||
287 | |||
288 | MODULE_DEVICE_TABLE(pci, cs5535_pci_tbl); | ||
289 | |||
290 | static struct pci_driver driver = { | ||
291 | .name = "CS5535_IDE", | ||
292 | .id_table = cs5535_pci_tbl, | ||
293 | .probe = cs5535_init_one, | ||
294 | }; | ||
295 | |||
296 | static int __init cs5535_ide_init(void) | ||
297 | { | ||
298 | return ide_pci_register_driver(&driver); | ||
299 | } | ||
300 | |||
301 | module_init(cs5535_ide_init); | ||
302 | |||
303 | MODULE_AUTHOR("AMD"); | ||
304 | MODULE_DESCRIPTION("PCI driver module for AMD/NS CS5535 IDE"); | ||
305 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c index 5a33513f3dd1..9f41ecd56338 100644 --- a/drivers/ide/pci/cy82c693.c +++ b/drivers/ide/pci/cy82c693.c | |||
@@ -469,7 +469,7 @@ static void __devinit init_hwif_cy82c693(ide_hwif_t *hwif) | |||
469 | 469 | ||
470 | static __devinitdata ide_hwif_t *primary; | 470 | static __devinitdata ide_hwif_t *primary; |
471 | 471 | ||
472 | void __devinit init_iops_cy82c693(ide_hwif_t *hwif) | 472 | static void __devinit init_iops_cy82c693(ide_hwif_t *hwif) |
473 | { | 473 | { |
474 | if (PCI_FUNC(hwif->pci_dev->devfn) == 1) | 474 | if (PCI_FUNC(hwif->pci_dev->devfn) == 1) |
475 | primary = hwif; | 475 | primary = hwif; |
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index 2b9961b88135..022d244f2eb0 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c | |||
@@ -701,6 +701,7 @@ static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name) | |||
701 | unsigned long barsize = pci_resource_len(dev, 5); | 701 | unsigned long barsize = pci_resource_len(dev, 5); |
702 | u8 tmpbyte = 0; | 702 | u8 tmpbyte = 0; |
703 | void __iomem *ioaddr; | 703 | void __iomem *ioaddr; |
704 | u32 tmp, irq_mask; | ||
704 | 705 | ||
705 | /* | 706 | /* |
706 | * Drop back to PIO if we can't map the mmio. Some | 707 | * Drop back to PIO if we can't map the mmio. Some |
@@ -726,6 +727,14 @@ static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name) | |||
726 | pci_set_drvdata(dev, (void *) ioaddr); | 727 | pci_set_drvdata(dev, (void *) ioaddr); |
727 | 728 | ||
728 | if (pdev_is_sata(dev)) { | 729 | if (pdev_is_sata(dev)) { |
730 | /* make sure IDE0/1 interrupts are not masked */ | ||
731 | irq_mask = (1 << 22) | (1 << 23); | ||
732 | tmp = readl(ioaddr + 0x48); | ||
733 | if (tmp & irq_mask) { | ||
734 | tmp &= ~irq_mask; | ||
735 | writel(tmp, ioaddr + 0x48); | ||
736 | readl(ioaddr + 0x48); /* flush */ | ||
737 | } | ||
729 | writel(0, ioaddr + 0x148); | 738 | writel(0, ioaddr + 0x148); |
730 | writel(0, ioaddr + 0x1C8); | 739 | writel(0, ioaddr + 0x1C8); |
731 | } | 740 | } |
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index aed5ca23fb22..5ea741f47fc8 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c | |||
@@ -31,7 +31,7 @@ | |||
31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | 31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
32 | * SOFTWARE. | 32 | * SOFTWARE. |
33 | * | 33 | * |
34 | * $Id: user_mad.c 2814 2005-07-06 19:14:09Z halr $ | 34 | * $Id: user_mad.c 4010 2005-11-09 23:11:56Z roland $ |
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include <linux/module.h> | 37 | #include <linux/module.h> |
@@ -110,13 +110,13 @@ struct ib_umad_device { | |||
110 | }; | 110 | }; |
111 | 111 | ||
112 | struct ib_umad_file { | 112 | struct ib_umad_file { |
113 | struct ib_umad_port *port; | 113 | struct ib_umad_port *port; |
114 | struct list_head recv_list; | 114 | struct list_head recv_list; |
115 | struct list_head port_list; | 115 | struct list_head port_list; |
116 | spinlock_t recv_lock; | 116 | spinlock_t recv_lock; |
117 | wait_queue_head_t recv_wait; | 117 | wait_queue_head_t recv_wait; |
118 | struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS]; | 118 | struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS]; |
119 | struct ib_mr *mr[IB_UMAD_MAX_AGENTS]; | 119 | int agents_dead; |
120 | }; | 120 | }; |
121 | 121 | ||
122 | struct ib_umad_packet { | 122 | struct ib_umad_packet { |
@@ -145,6 +145,12 @@ static void ib_umad_release_dev(struct kref *ref) | |||
145 | kfree(dev); | 145 | kfree(dev); |
146 | } | 146 | } |
147 | 147 | ||
148 | /* caller must hold port->mutex at least for reading */ | ||
149 | static struct ib_mad_agent *__get_agent(struct ib_umad_file *file, int id) | ||
150 | { | ||
151 | return file->agents_dead ? NULL : file->agent[id]; | ||
152 | } | ||
153 | |||
148 | static int queue_packet(struct ib_umad_file *file, | 154 | static int queue_packet(struct ib_umad_file *file, |
149 | struct ib_mad_agent *agent, | 155 | struct ib_mad_agent *agent, |
150 | struct ib_umad_packet *packet) | 156 | struct ib_umad_packet *packet) |
@@ -152,10 +158,11 @@ static int queue_packet(struct ib_umad_file *file, | |||
152 | int ret = 1; | 158 | int ret = 1; |
153 | 159 | ||
154 | down_read(&file->port->mutex); | 160 | down_read(&file->port->mutex); |
161 | |||
155 | for (packet->mad.hdr.id = 0; | 162 | for (packet->mad.hdr.id = 0; |
156 | packet->mad.hdr.id < IB_UMAD_MAX_AGENTS; | 163 | packet->mad.hdr.id < IB_UMAD_MAX_AGENTS; |
157 | packet->mad.hdr.id++) | 164 | packet->mad.hdr.id++) |
158 | if (agent == file->agent[packet->mad.hdr.id]) { | 165 | if (agent == __get_agent(file, packet->mad.hdr.id)) { |
159 | spin_lock_irq(&file->recv_lock); | 166 | spin_lock_irq(&file->recv_lock); |
160 | list_add_tail(&packet->list, &file->recv_list); | 167 | list_add_tail(&packet->list, &file->recv_list); |
161 | spin_unlock_irq(&file->recv_lock); | 168 | spin_unlock_irq(&file->recv_lock); |
@@ -327,7 +334,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, | |||
327 | 334 | ||
328 | down_read(&file->port->mutex); | 335 | down_read(&file->port->mutex); |
329 | 336 | ||
330 | agent = file->agent[packet->mad.hdr.id]; | 337 | agent = __get_agent(file, packet->mad.hdr.id); |
331 | if (!agent) { | 338 | if (!agent) { |
332 | ret = -EINVAL; | 339 | ret = -EINVAL; |
333 | goto err_up; | 340 | goto err_up; |
@@ -481,7 +488,7 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, unsigned long arg) | |||
481 | } | 488 | } |
482 | 489 | ||
483 | for (agent_id = 0; agent_id < IB_UMAD_MAX_AGENTS; ++agent_id) | 490 | for (agent_id = 0; agent_id < IB_UMAD_MAX_AGENTS; ++agent_id) |
484 | if (!file->agent[agent_id]) | 491 | if (!__get_agent(file, agent_id)) |
485 | goto found; | 492 | goto found; |
486 | 493 | ||
487 | ret = -ENOMEM; | 494 | ret = -ENOMEM; |
@@ -505,29 +512,15 @@ found: | |||
505 | goto out; | 512 | goto out; |
506 | } | 513 | } |
507 | 514 | ||
508 | file->agent[agent_id] = agent; | ||
509 | |||
510 | file->mr[agent_id] = ib_get_dma_mr(agent->qp->pd, IB_ACCESS_LOCAL_WRITE); | ||
511 | if (IS_ERR(file->mr[agent_id])) { | ||
512 | ret = -ENOMEM; | ||
513 | goto err; | ||
514 | } | ||
515 | |||
516 | if (put_user(agent_id, | 515 | if (put_user(agent_id, |
517 | (u32 __user *) (arg + offsetof(struct ib_user_mad_reg_req, id)))) { | 516 | (u32 __user *) (arg + offsetof(struct ib_user_mad_reg_req, id)))) { |
518 | ret = -EFAULT; | 517 | ret = -EFAULT; |
519 | goto err_mr; | 518 | ib_unregister_mad_agent(agent); |
519 | goto out; | ||
520 | } | 520 | } |
521 | 521 | ||
522 | file->agent[agent_id] = agent; | ||
522 | ret = 0; | 523 | ret = 0; |
523 | goto out; | ||
524 | |||
525 | err_mr: | ||
526 | ib_dereg_mr(file->mr[agent_id]); | ||
527 | |||
528 | err: | ||
529 | file->agent[agent_id] = NULL; | ||
530 | ib_unregister_mad_agent(agent); | ||
531 | 524 | ||
532 | out: | 525 | out: |
533 | up_write(&file->port->mutex); | 526 | up_write(&file->port->mutex); |
@@ -536,27 +529,29 @@ out: | |||
536 | 529 | ||
537 | static int ib_umad_unreg_agent(struct ib_umad_file *file, unsigned long arg) | 530 | static int ib_umad_unreg_agent(struct ib_umad_file *file, unsigned long arg) |
538 | { | 531 | { |
532 | struct ib_mad_agent *agent = NULL; | ||
539 | u32 id; | 533 | u32 id; |
540 | int ret = 0; | 534 | int ret = 0; |
541 | 535 | ||
542 | down_write(&file->port->mutex); | 536 | if (get_user(id, (u32 __user *) arg)) |
537 | return -EFAULT; | ||
543 | 538 | ||
544 | if (get_user(id, (u32 __user *) arg)) { | 539 | down_write(&file->port->mutex); |
545 | ret = -EFAULT; | ||
546 | goto out; | ||
547 | } | ||
548 | 540 | ||
549 | if (id < 0 || id >= IB_UMAD_MAX_AGENTS || !file->agent[id]) { | 541 | if (id < 0 || id >= IB_UMAD_MAX_AGENTS || !__get_agent(file, id)) { |
550 | ret = -EINVAL; | 542 | ret = -EINVAL; |
551 | goto out; | 543 | goto out; |
552 | } | 544 | } |
553 | 545 | ||
554 | ib_dereg_mr(file->mr[id]); | 546 | agent = file->agent[id]; |
555 | ib_unregister_mad_agent(file->agent[id]); | ||
556 | file->agent[id] = NULL; | 547 | file->agent[id] = NULL; |
557 | 548 | ||
558 | out: | 549 | out: |
559 | up_write(&file->port->mutex); | 550 | up_write(&file->port->mutex); |
551 | |||
552 | if (agent) | ||
553 | ib_unregister_mad_agent(agent); | ||
554 | |||
560 | return ret; | 555 | return ret; |
561 | } | 556 | } |
562 | 557 | ||
@@ -621,23 +616,29 @@ static int ib_umad_close(struct inode *inode, struct file *filp) | |||
621 | struct ib_umad_file *file = filp->private_data; | 616 | struct ib_umad_file *file = filp->private_data; |
622 | struct ib_umad_device *dev = file->port->umad_dev; | 617 | struct ib_umad_device *dev = file->port->umad_dev; |
623 | struct ib_umad_packet *packet, *tmp; | 618 | struct ib_umad_packet *packet, *tmp; |
619 | int already_dead; | ||
624 | int i; | 620 | int i; |
625 | 621 | ||
626 | down_write(&file->port->mutex); | 622 | down_write(&file->port->mutex); |
627 | for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i) | 623 | |
628 | if (file->agent[i]) { | 624 | already_dead = file->agents_dead; |
629 | ib_dereg_mr(file->mr[i]); | 625 | file->agents_dead = 1; |
630 | ib_unregister_mad_agent(file->agent[i]); | ||
631 | } | ||
632 | 626 | ||
633 | list_for_each_entry_safe(packet, tmp, &file->recv_list, list) | 627 | list_for_each_entry_safe(packet, tmp, &file->recv_list, list) |
634 | kfree(packet); | 628 | kfree(packet); |
635 | 629 | ||
636 | list_del(&file->port_list); | 630 | list_del(&file->port_list); |
637 | up_write(&file->port->mutex); | ||
638 | 631 | ||
639 | kfree(file); | 632 | downgrade_write(&file->port->mutex); |
633 | |||
634 | if (!already_dead) | ||
635 | for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i) | ||
636 | if (file->agent[i]) | ||
637 | ib_unregister_mad_agent(file->agent[i]); | ||
638 | |||
639 | up_read(&file->port->mutex); | ||
640 | 640 | ||
641 | kfree(file); | ||
641 | kref_put(&dev->ref, ib_umad_release_dev); | 642 | kref_put(&dev->ref, ib_umad_release_dev); |
642 | 643 | ||
643 | return 0; | 644 | return 0; |
@@ -801,7 +802,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, | |||
801 | goto err_class; | 802 | goto err_class; |
802 | port->sm_dev->owner = THIS_MODULE; | 803 | port->sm_dev->owner = THIS_MODULE; |
803 | port->sm_dev->ops = &umad_sm_fops; | 804 | port->sm_dev->ops = &umad_sm_fops; |
804 | kobject_set_name(&port->dev->kobj, "issm%d", port->dev_num); | 805 | kobject_set_name(&port->sm_dev->kobj, "issm%d", port->dev_num); |
805 | if (cdev_add(port->sm_dev, base_dev + port->dev_num + IB_UMAD_MAX_PORTS, 1)) | 806 | if (cdev_add(port->sm_dev, base_dev + port->dev_num + IB_UMAD_MAX_PORTS, 1)) |
806 | goto err_sm_cdev; | 807 | goto err_sm_cdev; |
807 | 808 | ||
@@ -863,14 +864,36 @@ static void ib_umad_kill_port(struct ib_umad_port *port) | |||
863 | 864 | ||
864 | port->ib_dev = NULL; | 865 | port->ib_dev = NULL; |
865 | 866 | ||
866 | list_for_each_entry(file, &port->file_list, port_list) | 867 | /* |
867 | for (id = 0; id < IB_UMAD_MAX_AGENTS; ++id) { | 868 | * Now go through the list of files attached to this port and |
868 | if (!file->agent[id]) | 869 | * unregister all of their MAD agents. We need to hold |
869 | continue; | 870 | * port->mutex while doing this to avoid racing with |
870 | ib_dereg_mr(file->mr[id]); | 871 | * ib_umad_close(), but we can't hold the mutex for writing |
871 | ib_unregister_mad_agent(file->agent[id]); | 872 | * while calling ib_unregister_mad_agent(), since that might |
872 | file->agent[id] = NULL; | 873 | * deadlock by calling back into queue_packet(). So we |
873 | } | 874 | * downgrade our lock to a read lock, and then drop and |
875 | * reacquire the write lock for the next iteration. | ||
876 | * | ||
877 | * We do list_del_init() on the file's list_head so that the | ||
878 | * list_del in ib_umad_close() is still OK, even after the | ||
879 | * file is removed from the list. | ||
880 | */ | ||
881 | while (!list_empty(&port->file_list)) { | ||
882 | file = list_entry(port->file_list.next, struct ib_umad_file, | ||
883 | port_list); | ||
884 | |||
885 | file->agents_dead = 1; | ||
886 | list_del_init(&file->port_list); | ||
887 | |||
888 | downgrade_write(&port->mutex); | ||
889 | |||
890 | for (id = 0; id < IB_UMAD_MAX_AGENTS; ++id) | ||
891 | if (file->agent[id]) | ||
892 | ib_unregister_mad_agent(file->agent[id]); | ||
893 | |||
894 | up_read(&port->mutex); | ||
895 | down_write(&port->mutex); | ||
896 | } | ||
874 | 897 | ||
875 | up_write(&port->mutex); | 898 | up_write(&port->mutex); |
876 | 899 | ||
@@ -913,7 +936,7 @@ static void ib_umad_add_one(struct ib_device *device) | |||
913 | 936 | ||
914 | err: | 937 | err: |
915 | while (--i >= s) | 938 | while (--i >= s) |
916 | ib_umad_kill_port(&umad_dev->port[i]); | 939 | ib_umad_kill_port(&umad_dev->port[i - s]); |
917 | 940 | ||
918 | kref_put(&umad_dev->ref, ib_umad_release_dev); | 941 | kref_put(&umad_dev->ref, ib_umad_release_dev); |
919 | } | 942 | } |
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 63a74151c60b..ed45da892b1c 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c | |||
@@ -708,7 +708,7 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file, | |||
708 | resp->wc[i].opcode = wc[i].opcode; | 708 | resp->wc[i].opcode = wc[i].opcode; |
709 | resp->wc[i].vendor_err = wc[i].vendor_err; | 709 | resp->wc[i].vendor_err = wc[i].vendor_err; |
710 | resp->wc[i].byte_len = wc[i].byte_len; | 710 | resp->wc[i].byte_len = wc[i].byte_len; |
711 | resp->wc[i].imm_data = wc[i].imm_data; | 711 | resp->wc[i].imm_data = (__u32 __force) wc[i].imm_data; |
712 | resp->wc[i].qp_num = wc[i].qp_num; | 712 | resp->wc[i].qp_num = wc[i].qp_num; |
713 | resp->wc[i].src_qp = wc[i].src_qp; | 713 | resp->wc[i].src_qp = wc[i].src_qp; |
714 | resp->wc[i].wc_flags = wc[i].wc_flags; | 714 | resp->wc[i].wc_flags = wc[i].wc_flags; |
@@ -908,7 +908,12 @@ retry: | |||
908 | if (ret) | 908 | if (ret) |
909 | goto err_destroy; | 909 | goto err_destroy; |
910 | 910 | ||
911 | resp.qp_handle = uobj->uobject.id; | 911 | resp.qp_handle = uobj->uobject.id; |
912 | resp.max_recv_sge = attr.cap.max_recv_sge; | ||
913 | resp.max_send_sge = attr.cap.max_send_sge; | ||
914 | resp.max_recv_wr = attr.cap.max_recv_wr; | ||
915 | resp.max_send_wr = attr.cap.max_send_wr; | ||
916 | resp.max_inline_data = attr.cap.max_inline_data; | ||
912 | 917 | ||
913 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | 918 | if (copy_to_user((void __user *) (unsigned long) cmd.response, |
914 | &resp, sizeof resp)) { | 919 | &resp, sizeof resp)) { |
@@ -1135,7 +1140,7 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, | |||
1135 | next->num_sge = user_wr->num_sge; | 1140 | next->num_sge = user_wr->num_sge; |
1136 | next->opcode = user_wr->opcode; | 1141 | next->opcode = user_wr->opcode; |
1137 | next->send_flags = user_wr->send_flags; | 1142 | next->send_flags = user_wr->send_flags; |
1138 | next->imm_data = user_wr->imm_data; | 1143 | next->imm_data = (__be32 __force) user_wr->imm_data; |
1139 | 1144 | ||
1140 | if (qp->qp_type == IB_QPT_UD) { | 1145 | if (qp->qp_type == IB_QPT_UD) { |
1141 | next->wr.ud.ah = idr_find(&ib_uverbs_ah_idr, | 1146 | next->wr.ud.ah = idr_find(&ib_uverbs_ah_idr, |
@@ -1701,7 +1706,6 @@ ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file, | |||
1701 | } | 1706 | } |
1702 | 1707 | ||
1703 | attr.max_wr = cmd.max_wr; | 1708 | attr.max_wr = cmd.max_wr; |
1704 | attr.max_sge = cmd.max_sge; | ||
1705 | attr.srq_limit = cmd.srq_limit; | 1709 | attr.srq_limit = cmd.srq_limit; |
1706 | 1710 | ||
1707 | ret = ib_modify_srq(srq, &attr, cmd.attr_mask); | 1711 | ret = ib_modify_srq(srq, &attr, cmd.attr_mask); |
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 4186cc888ea5..4c15e112736c 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c | |||
@@ -325,16 +325,8 @@ EXPORT_SYMBOL(ib_destroy_cq); | |||
325 | int ib_resize_cq(struct ib_cq *cq, | 325 | int ib_resize_cq(struct ib_cq *cq, |
326 | int cqe) | 326 | int cqe) |
327 | { | 327 | { |
328 | int ret; | 328 | return cq->device->resize_cq ? |
329 | 329 | cq->device->resize_cq(cq, cqe) : -ENOSYS; | |
330 | if (!cq->device->resize_cq) | ||
331 | return -ENOSYS; | ||
332 | |||
333 | ret = cq->device->resize_cq(cq, &cqe); | ||
334 | if (!ret) | ||
335 | cq->cqe = cqe; | ||
336 | |||
337 | return ret; | ||
338 | } | 330 | } |
339 | EXPORT_SYMBOL(ib_resize_cq); | 331 | EXPORT_SYMBOL(ib_resize_cq); |
340 | 332 | ||
diff --git a/drivers/infiniband/hw/mthca/mthca_catas.c b/drivers/infiniband/hw/mthca/mthca_catas.c index 25ebab64bc42..c3bec7490f52 100644 --- a/drivers/infiniband/hw/mthca/mthca_catas.c +++ b/drivers/infiniband/hw/mthca/mthca_catas.c | |||
@@ -97,7 +97,7 @@ static void poll_catas(unsigned long dev_ptr) | |||
97 | } | 97 | } |
98 | 98 | ||
99 | spin_lock_irqsave(&catas_lock, flags); | 99 | spin_lock_irqsave(&catas_lock, flags); |
100 | if (dev->catas_err.stop) | 100 | if (!dev->catas_err.stop) |
101 | mod_timer(&dev->catas_err.timer, | 101 | mod_timer(&dev->catas_err.timer, |
102 | jiffies + MTHCA_CATAS_POLL_INTERVAL); | 102 | jiffies + MTHCA_CATAS_POLL_INTERVAL); |
103 | spin_unlock_irqrestore(&catas_lock, flags); | 103 | spin_unlock_irqrestore(&catas_lock, flags); |
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c index 49f211d55df7..9ed34587fc5c 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/drivers/infiniband/hw/mthca/mthca_cmd.c | |||
@@ -1060,6 +1060,8 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev, | |||
1060 | dev_lim->hca.arbel.resize_srq = field & 1; | 1060 | dev_lim->hca.arbel.resize_srq = field & 1; |
1061 | MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SG_RQ_OFFSET); | 1061 | MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SG_RQ_OFFSET); |
1062 | dev_lim->max_sg = min_t(int, field, dev_lim->max_sg); | 1062 | dev_lim->max_sg = min_t(int, field, dev_lim->max_sg); |
1063 | MTHCA_GET(size, outbox, QUERY_DEV_LIM_MAX_DESC_SZ_RQ_OFFSET); | ||
1064 | dev_lim->max_desc_sz = min_t(int, size, dev_lim->max_desc_sz); | ||
1063 | MTHCA_GET(size, outbox, QUERY_DEV_LIM_MPT_ENTRY_SZ_OFFSET); | 1065 | MTHCA_GET(size, outbox, QUERY_DEV_LIM_MPT_ENTRY_SZ_OFFSET); |
1064 | dev_lim->mpt_entry_sz = size; | 1066 | dev_lim->mpt_entry_sz = size; |
1065 | MTHCA_GET(field, outbox, QUERY_DEV_LIM_PBL_SZ_OFFSET); | 1067 | MTHCA_GET(field, outbox, QUERY_DEV_LIM_PBL_SZ_OFFSET); |
diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c index f98e23555826..4a8adcef2079 100644 --- a/drivers/infiniband/hw/mthca/mthca_cq.c +++ b/drivers/infiniband/hw/mthca/mthca_cq.c | |||
@@ -258,7 +258,7 @@ void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn, | |||
258 | { | 258 | { |
259 | struct mthca_cq *cq; | 259 | struct mthca_cq *cq; |
260 | struct mthca_cqe *cqe; | 260 | struct mthca_cqe *cqe; |
261 | int prod_index; | 261 | u32 prod_index; |
262 | int nfreed = 0; | 262 | int nfreed = 0; |
263 | 263 | ||
264 | spin_lock_irq(&dev->cq_table.lock); | 264 | spin_lock_irq(&dev->cq_table.lock); |
@@ -293,19 +293,15 @@ void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn, | |||
293 | * Now sweep backwards through the CQ, removing CQ entries | 293 | * Now sweep backwards through the CQ, removing CQ entries |
294 | * that match our QP by copying older entries on top of them. | 294 | * that match our QP by copying older entries on top of them. |
295 | */ | 295 | */ |
296 | while (prod_index > cq->cons_index) { | 296 | while ((int) --prod_index - (int) cq->cons_index >= 0) { |
297 | cqe = get_cqe(cq, (prod_index - 1) & cq->ibcq.cqe); | 297 | cqe = get_cqe(cq, prod_index & cq->ibcq.cqe); |
298 | if (cqe->my_qpn == cpu_to_be32(qpn)) { | 298 | if (cqe->my_qpn == cpu_to_be32(qpn)) { |
299 | if (srq) | 299 | if (srq) |
300 | mthca_free_srq_wqe(srq, be32_to_cpu(cqe->wqe)); | 300 | mthca_free_srq_wqe(srq, be32_to_cpu(cqe->wqe)); |
301 | ++nfreed; | 301 | ++nfreed; |
302 | } | 302 | } else if (nfreed) |
303 | else if (nfreed) | 303 | memcpy(get_cqe(cq, (prod_index + nfreed) & cq->ibcq.cqe), |
304 | memcpy(get_cqe(cq, (prod_index - 1 + nfreed) & | 304 | cqe, MTHCA_CQ_ENTRY_SIZE); |
305 | cq->ibcq.cqe), | ||
306 | cqe, | ||
307 | MTHCA_CQ_ENTRY_SIZE); | ||
308 | --prod_index; | ||
309 | } | 305 | } |
310 | 306 | ||
311 | if (nfreed) { | 307 | if (nfreed) { |
diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h index e7e5d3b4f004..497ff794ef6a 100644 --- a/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/drivers/infiniband/hw/mthca/mthca_dev.h | |||
@@ -131,6 +131,7 @@ struct mthca_limits { | |||
131 | int max_sg; | 131 | int max_sg; |
132 | int num_qps; | 132 | int num_qps; |
133 | int max_wqes; | 133 | int max_wqes; |
134 | int max_desc_sz; | ||
134 | int max_qp_init_rdma; | 135 | int max_qp_init_rdma; |
135 | int reserved_qps; | 136 | int reserved_qps; |
136 | int num_srqs; | 137 | int num_srqs; |
@@ -154,6 +155,7 @@ struct mthca_limits { | |||
154 | int reserved_mcgs; | 155 | int reserved_mcgs; |
155 | int num_pds; | 156 | int num_pds; |
156 | int reserved_pds; | 157 | int reserved_pds; |
158 | u32 page_size_cap; | ||
157 | u32 flags; | 159 | u32 flags; |
158 | u8 port_width_cap; | 160 | u8 port_width_cap; |
159 | }; | 161 | }; |
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 45c6328e780c..147f248a8073 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c | |||
@@ -168,6 +168,7 @@ static int __devinit mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim | |||
168 | mdev->limits.max_srq_wqes = dev_lim->max_srq_sz; | 168 | mdev->limits.max_srq_wqes = dev_lim->max_srq_sz; |
169 | mdev->limits.reserved_srqs = dev_lim->reserved_srqs; | 169 | mdev->limits.reserved_srqs = dev_lim->reserved_srqs; |
170 | mdev->limits.reserved_eecs = dev_lim->reserved_eecs; | 170 | mdev->limits.reserved_eecs = dev_lim->reserved_eecs; |
171 | mdev->limits.max_desc_sz = dev_lim->max_desc_sz; | ||
171 | /* | 172 | /* |
172 | * Subtract 1 from the limit because we need to allocate a | 173 | * Subtract 1 from the limit because we need to allocate a |
173 | * spare CQE so the HCA HW can tell the difference between an | 174 | * spare CQE so the HCA HW can tell the difference between an |
@@ -181,6 +182,7 @@ static int __devinit mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim | |||
181 | mdev->limits.reserved_uars = dev_lim->reserved_uars; | 182 | mdev->limits.reserved_uars = dev_lim->reserved_uars; |
182 | mdev->limits.reserved_pds = dev_lim->reserved_pds; | 183 | mdev->limits.reserved_pds = dev_lim->reserved_pds; |
183 | mdev->limits.port_width_cap = dev_lim->max_port_width; | 184 | mdev->limits.port_width_cap = dev_lim->max_port_width; |
185 | mdev->limits.page_size_cap = ~(u32) (dev_lim->min_page_sz - 1); | ||
184 | mdev->limits.flags = dev_lim->flags; | 186 | mdev->limits.flags = dev_lim->flags; |
185 | 187 | ||
186 | /* IB_DEVICE_RESIZE_MAX_WR not supported by driver. | 188 | /* IB_DEVICE_RESIZE_MAX_WR not supported by driver. |
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 6b0166668269..4cc7e2846df1 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c | |||
@@ -90,6 +90,7 @@ static int mthca_query_device(struct ib_device *ibdev, | |||
90 | memcpy(&props->node_guid, out_mad->data + 12, 8); | 90 | memcpy(&props->node_guid, out_mad->data + 12, 8); |
91 | 91 | ||
92 | props->max_mr_size = ~0ull; | 92 | props->max_mr_size = ~0ull; |
93 | props->page_size_cap = mdev->limits.page_size_cap; | ||
93 | props->max_qp = mdev->limits.num_qps - mdev->limits.reserved_qps; | 94 | props->max_qp = mdev->limits.num_qps - mdev->limits.reserved_qps; |
94 | props->max_qp_wr = mdev->limits.max_wqes; | 95 | props->max_qp_wr = mdev->limits.max_wqes; |
95 | props->max_sge = mdev->limits.max_sg; | 96 | props->max_sge = mdev->limits.max_sg; |
@@ -615,11 +616,11 @@ static struct ib_qp *mthca_create_qp(struct ib_pd *pd, | |||
615 | return ERR_PTR(err); | 616 | return ERR_PTR(err); |
616 | } | 617 | } |
617 | 618 | ||
618 | init_attr->cap.max_inline_data = 0; | ||
619 | init_attr->cap.max_send_wr = qp->sq.max; | 619 | init_attr->cap.max_send_wr = qp->sq.max; |
620 | init_attr->cap.max_recv_wr = qp->rq.max; | 620 | init_attr->cap.max_recv_wr = qp->rq.max; |
621 | init_attr->cap.max_send_sge = qp->sq.max_gs; | 621 | init_attr->cap.max_send_sge = qp->sq.max_gs; |
622 | init_attr->cap.max_recv_sge = qp->rq.max_gs; | 622 | init_attr->cap.max_recv_sge = qp->rq.max_gs; |
623 | init_attr->cap.max_inline_data = qp->max_inline_data; | ||
623 | 624 | ||
624 | return &qp->ibqp; | 625 | return &qp->ibqp; |
625 | } | 626 | } |
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h index bcd4b01a339c..1e73947b4702 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.h +++ b/drivers/infiniband/hw/mthca/mthca_provider.h | |||
@@ -251,6 +251,7 @@ struct mthca_qp { | |||
251 | struct mthca_wq sq; | 251 | struct mthca_wq sq; |
252 | enum ib_sig_type sq_policy; | 252 | enum ib_sig_type sq_policy; |
253 | int send_wqe_offset; | 253 | int send_wqe_offset; |
254 | int max_inline_data; | ||
254 | 255 | ||
255 | u64 *wrid; | 256 | u64 *wrid; |
256 | union mthca_buf queue; | 257 | union mthca_buf queue; |
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 8852ea477c21..760c418d5bc9 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c | |||
@@ -885,6 +885,48 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) | |||
885 | return err; | 885 | return err; |
886 | } | 886 | } |
887 | 887 | ||
888 | static void mthca_adjust_qp_caps(struct mthca_dev *dev, | ||
889 | struct mthca_pd *pd, | ||
890 | struct mthca_qp *qp) | ||
891 | { | ||
892 | int max_data_size; | ||
893 | |||
894 | /* | ||
895 | * Calculate the maximum size of WQE s/g segments, excluding | ||
896 | * the next segment and other non-data segments. | ||
897 | */ | ||
898 | max_data_size = min(dev->limits.max_desc_sz, 1 << qp->sq.wqe_shift) - | ||
899 | sizeof (struct mthca_next_seg); | ||
900 | |||
901 | switch (qp->transport) { | ||
902 | case MLX: | ||
903 | max_data_size -= 2 * sizeof (struct mthca_data_seg); | ||
904 | break; | ||
905 | |||
906 | case UD: | ||
907 | if (mthca_is_memfree(dev)) | ||
908 | max_data_size -= sizeof (struct mthca_arbel_ud_seg); | ||
909 | else | ||
910 | max_data_size -= sizeof (struct mthca_tavor_ud_seg); | ||
911 | break; | ||
912 | |||
913 | default: | ||
914 | max_data_size -= sizeof (struct mthca_raddr_seg); | ||
915 | break; | ||
916 | } | ||
917 | |||
918 | /* We don't support inline data for kernel QPs (yet). */ | ||
919 | if (!pd->ibpd.uobject) | ||
920 | qp->max_inline_data = 0; | ||
921 | else | ||
922 | qp->max_inline_data = max_data_size - MTHCA_INLINE_HEADER_SIZE; | ||
923 | |||
924 | qp->sq.max_gs = max_data_size / sizeof (struct mthca_data_seg); | ||
925 | qp->rq.max_gs = (min(dev->limits.max_desc_sz, 1 << qp->rq.wqe_shift) - | ||
926 | sizeof (struct mthca_next_seg)) / | ||
927 | sizeof (struct mthca_data_seg); | ||
928 | } | ||
929 | |||
888 | /* | 930 | /* |
889 | * Allocate and register buffer for WQEs. qp->rq.max, sq.max, | 931 | * Allocate and register buffer for WQEs. qp->rq.max, sq.max, |
890 | * rq.max_gs and sq.max_gs must all be assigned. | 932 | * rq.max_gs and sq.max_gs must all be assigned. |
@@ -902,27 +944,53 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev, | |||
902 | size = sizeof (struct mthca_next_seg) + | 944 | size = sizeof (struct mthca_next_seg) + |
903 | qp->rq.max_gs * sizeof (struct mthca_data_seg); | 945 | qp->rq.max_gs * sizeof (struct mthca_data_seg); |
904 | 946 | ||
947 | if (size > dev->limits.max_desc_sz) | ||
948 | return -EINVAL; | ||
949 | |||
905 | for (qp->rq.wqe_shift = 6; 1 << qp->rq.wqe_shift < size; | 950 | for (qp->rq.wqe_shift = 6; 1 << qp->rq.wqe_shift < size; |
906 | qp->rq.wqe_shift++) | 951 | qp->rq.wqe_shift++) |
907 | ; /* nothing */ | 952 | ; /* nothing */ |
908 | 953 | ||
909 | size = sizeof (struct mthca_next_seg) + | 954 | size = qp->sq.max_gs * sizeof (struct mthca_data_seg); |
910 | qp->sq.max_gs * sizeof (struct mthca_data_seg); | ||
911 | switch (qp->transport) { | 955 | switch (qp->transport) { |
912 | case MLX: | 956 | case MLX: |
913 | size += 2 * sizeof (struct mthca_data_seg); | 957 | size += 2 * sizeof (struct mthca_data_seg); |
914 | break; | 958 | break; |
959 | |||
915 | case UD: | 960 | case UD: |
916 | if (mthca_is_memfree(dev)) | 961 | size += mthca_is_memfree(dev) ? |
917 | size += sizeof (struct mthca_arbel_ud_seg); | 962 | sizeof (struct mthca_arbel_ud_seg) : |
918 | else | 963 | sizeof (struct mthca_tavor_ud_seg); |
919 | size += sizeof (struct mthca_tavor_ud_seg); | ||
920 | break; | 964 | break; |
965 | |||
966 | case UC: | ||
967 | size += sizeof (struct mthca_raddr_seg); | ||
968 | break; | ||
969 | |||
970 | case RC: | ||
971 | size += sizeof (struct mthca_raddr_seg); | ||
972 | /* | ||
973 | * An atomic op will require an atomic segment, a | ||
974 | * remote address segment and one scatter entry. | ||
975 | */ | ||
976 | size = max_t(int, size, | ||
977 | sizeof (struct mthca_atomic_seg) + | ||
978 | sizeof (struct mthca_raddr_seg) + | ||
979 | sizeof (struct mthca_data_seg)); | ||
980 | break; | ||
981 | |||
921 | default: | 982 | default: |
922 | /* bind seg is as big as atomic + raddr segs */ | 983 | break; |
923 | size += sizeof (struct mthca_bind_seg); | ||
924 | } | 984 | } |
925 | 985 | ||
986 | /* Make sure that we have enough space for a bind request */ | ||
987 | size = max_t(int, size, sizeof (struct mthca_bind_seg)); | ||
988 | |||
989 | size += sizeof (struct mthca_next_seg); | ||
990 | |||
991 | if (size > dev->limits.max_desc_sz) | ||
992 | return -EINVAL; | ||
993 | |||
926 | for (qp->sq.wqe_shift = 6; 1 << qp->sq.wqe_shift < size; | 994 | for (qp->sq.wqe_shift = 6; 1 << qp->sq.wqe_shift < size; |
927 | qp->sq.wqe_shift++) | 995 | qp->sq.wqe_shift++) |
928 | ; /* nothing */ | 996 | ; /* nothing */ |
@@ -1066,6 +1134,8 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev, | |||
1066 | return ret; | 1134 | return ret; |
1067 | } | 1135 | } |
1068 | 1136 | ||
1137 | mthca_adjust_qp_caps(dev, pd, qp); | ||
1138 | |||
1069 | /* | 1139 | /* |
1070 | * If this is a userspace QP, we're done now. The doorbells | 1140 | * If this is a userspace QP, we're done now. The doorbells |
1071 | * will be allocated and buffers will be initialized in | 1141 | * will be allocated and buffers will be initialized in |
@@ -1486,8 +1556,8 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |||
1486 | } | 1556 | } |
1487 | 1557 | ||
1488 | wqe += sizeof (struct mthca_atomic_seg); | 1558 | wqe += sizeof (struct mthca_atomic_seg); |
1489 | size += sizeof (struct mthca_raddr_seg) / 16 + | 1559 | size += (sizeof (struct mthca_raddr_seg) + |
1490 | sizeof (struct mthca_atomic_seg); | 1560 | sizeof (struct mthca_atomic_seg)) / 16; |
1491 | break; | 1561 | break; |
1492 | 1562 | ||
1493 | case IB_WR_RDMA_WRITE: | 1563 | case IB_WR_RDMA_WRITE: |
@@ -1637,6 +1707,7 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, | |||
1637 | { | 1707 | { |
1638 | struct mthca_dev *dev = to_mdev(ibqp->device); | 1708 | struct mthca_dev *dev = to_mdev(ibqp->device); |
1639 | struct mthca_qp *qp = to_mqp(ibqp); | 1709 | struct mthca_qp *qp = to_mqp(ibqp); |
1710 | __be32 doorbell[2]; | ||
1640 | unsigned long flags; | 1711 | unsigned long flags; |
1641 | int err = 0; | 1712 | int err = 0; |
1642 | int nreq; | 1713 | int nreq; |
@@ -1654,6 +1725,22 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, | |||
1654 | ind = qp->rq.next_ind; | 1725 | ind = qp->rq.next_ind; |
1655 | 1726 | ||
1656 | for (nreq = 0; wr; ++nreq, wr = wr->next) { | 1727 | for (nreq = 0; wr; ++nreq, wr = wr->next) { |
1728 | if (unlikely(nreq == MTHCA_TAVOR_MAX_WQES_PER_RECV_DB)) { | ||
1729 | nreq = 0; | ||
1730 | |||
1731 | doorbell[0] = cpu_to_be32((qp->rq.next_ind << qp->rq.wqe_shift) | size0); | ||
1732 | doorbell[1] = cpu_to_be32(qp->qpn << 8); | ||
1733 | |||
1734 | wmb(); | ||
1735 | |||
1736 | mthca_write64(doorbell, | ||
1737 | dev->kar + MTHCA_RECEIVE_DOORBELL, | ||
1738 | MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); | ||
1739 | |||
1740 | qp->rq.head += MTHCA_TAVOR_MAX_WQES_PER_RECV_DB; | ||
1741 | size0 = 0; | ||
1742 | } | ||
1743 | |||
1657 | if (mthca_wq_overflow(&qp->rq, nreq, qp->ibqp.recv_cq)) { | 1744 | if (mthca_wq_overflow(&qp->rq, nreq, qp->ibqp.recv_cq)) { |
1658 | mthca_err(dev, "RQ %06x full (%u head, %u tail," | 1745 | mthca_err(dev, "RQ %06x full (%u head, %u tail," |
1659 | " %d max, %d nreq)\n", qp->qpn, | 1746 | " %d max, %d nreq)\n", qp->qpn, |
@@ -1711,8 +1798,6 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, | |||
1711 | 1798 | ||
1712 | out: | 1799 | out: |
1713 | if (likely(nreq)) { | 1800 | if (likely(nreq)) { |
1714 | __be32 doorbell[2]; | ||
1715 | |||
1716 | doorbell[0] = cpu_to_be32((qp->rq.next_ind << qp->rq.wqe_shift) | size0); | 1801 | doorbell[0] = cpu_to_be32((qp->rq.next_ind << qp->rq.wqe_shift) | size0); |
1717 | doorbell[1] = cpu_to_be32((qp->qpn << 8) | nreq); | 1802 | doorbell[1] = cpu_to_be32((qp->qpn << 8) | nreq); |
1718 | 1803 | ||
@@ -1806,8 +1891,8 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |||
1806 | } | 1891 | } |
1807 | 1892 | ||
1808 | wqe += sizeof (struct mthca_atomic_seg); | 1893 | wqe += sizeof (struct mthca_atomic_seg); |
1809 | size += sizeof (struct mthca_raddr_seg) / 16 + | 1894 | size += (sizeof (struct mthca_raddr_seg) + |
1810 | sizeof (struct mthca_atomic_seg); | 1895 | sizeof (struct mthca_atomic_seg)) / 16; |
1811 | break; | 1896 | break; |
1812 | 1897 | ||
1813 | case IB_WR_RDMA_READ: | 1898 | case IB_WR_RDMA_READ: |
diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c index 26d5161fde07..f7d234295efe 100644 --- a/drivers/infiniband/hw/mthca/mthca_srq.c +++ b/drivers/infiniband/hw/mthca/mthca_srq.c | |||
@@ -417,6 +417,7 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, | |||
417 | { | 417 | { |
418 | struct mthca_dev *dev = to_mdev(ibsrq->device); | 418 | struct mthca_dev *dev = to_mdev(ibsrq->device); |
419 | struct mthca_srq *srq = to_msrq(ibsrq); | 419 | struct mthca_srq *srq = to_msrq(ibsrq); |
420 | __be32 doorbell[2]; | ||
420 | unsigned long flags; | 421 | unsigned long flags; |
421 | int err = 0; | 422 | int err = 0; |
422 | int first_ind; | 423 | int first_ind; |
@@ -432,6 +433,25 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, | |||
432 | first_ind = srq->first_free; | 433 | first_ind = srq->first_free; |
433 | 434 | ||
434 | for (nreq = 0; wr; ++nreq, wr = wr->next) { | 435 | for (nreq = 0; wr; ++nreq, wr = wr->next) { |
436 | if (unlikely(nreq == MTHCA_TAVOR_MAX_WQES_PER_RECV_DB)) { | ||
437 | nreq = 0; | ||
438 | |||
439 | doorbell[0] = cpu_to_be32(first_ind << srq->wqe_shift); | ||
440 | doorbell[1] = cpu_to_be32(srq->srqn << 8); | ||
441 | |||
442 | /* | ||
443 | * Make sure that descriptors are written | ||
444 | * before doorbell is rung. | ||
445 | */ | ||
446 | wmb(); | ||
447 | |||
448 | mthca_write64(doorbell, | ||
449 | dev->kar + MTHCA_RECEIVE_DOORBELL, | ||
450 | MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); | ||
451 | |||
452 | first_ind = srq->first_free; | ||
453 | } | ||
454 | |||
435 | ind = srq->first_free; | 455 | ind = srq->first_free; |
436 | 456 | ||
437 | if (ind < 0) { | 457 | if (ind < 0) { |
@@ -494,8 +514,6 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, | |||
494 | } | 514 | } |
495 | 515 | ||
496 | if (likely(nreq)) { | 516 | if (likely(nreq)) { |
497 | __be32 doorbell[2]; | ||
498 | |||
499 | doorbell[0] = cpu_to_be32(first_ind << srq->wqe_shift); | 517 | doorbell[0] = cpu_to_be32(first_ind << srq->wqe_shift); |
500 | doorbell[1] = cpu_to_be32((srq->srqn << 8) | nreq); | 518 | doorbell[1] = cpu_to_be32((srq->srqn << 8) | nreq); |
501 | 519 | ||
diff --git a/drivers/infiniband/hw/mthca/mthca_wqe.h b/drivers/infiniband/hw/mthca/mthca_wqe.h index 1f4c0ff28f79..73f1c0b9021e 100644 --- a/drivers/infiniband/hw/mthca/mthca_wqe.h +++ b/drivers/infiniband/hw/mthca/mthca_wqe.h | |||
@@ -49,7 +49,8 @@ enum { | |||
49 | }; | 49 | }; |
50 | 50 | ||
51 | enum { | 51 | enum { |
52 | MTHCA_INVAL_LKEY = 0x100 | 52 | MTHCA_INVAL_LKEY = 0x100, |
53 | MTHCA_TAVOR_MAX_WQES_PER_RECV_DB = 256 | ||
53 | }; | 54 | }; |
54 | 55 | ||
55 | struct mthca_next_seg { | 56 | struct mthca_next_seg { |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 0095acc0fbbe..9923a15a9996 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h | |||
@@ -179,6 +179,7 @@ struct ipoib_dev_priv { | |||
179 | #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG | 179 | #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG |
180 | struct list_head fs_list; | 180 | struct list_head fs_list; |
181 | struct dentry *mcg_dentry; | 181 | struct dentry *mcg_dentry; |
182 | struct dentry *path_dentry; | ||
182 | #endif | 183 | #endif |
183 | }; | 184 | }; |
184 | 185 | ||
@@ -270,7 +271,6 @@ void ipoib_mcast_dev_flush(struct net_device *dev); | |||
270 | 271 | ||
271 | #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG | 272 | #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG |
272 | struct ipoib_mcast_iter *ipoib_mcast_iter_init(struct net_device *dev); | 273 | struct ipoib_mcast_iter *ipoib_mcast_iter_init(struct net_device *dev); |
273 | void ipoib_mcast_iter_free(struct ipoib_mcast_iter *iter); | ||
274 | int ipoib_mcast_iter_next(struct ipoib_mcast_iter *iter); | 274 | int ipoib_mcast_iter_next(struct ipoib_mcast_iter *iter); |
275 | void ipoib_mcast_iter_read(struct ipoib_mcast_iter *iter, | 275 | void ipoib_mcast_iter_read(struct ipoib_mcast_iter *iter, |
276 | union ib_gid *gid, | 276 | union ib_gid *gid, |
@@ -278,6 +278,11 @@ void ipoib_mcast_iter_read(struct ipoib_mcast_iter *iter, | |||
278 | unsigned int *queuelen, | 278 | unsigned int *queuelen, |
279 | unsigned int *complete, | 279 | unsigned int *complete, |
280 | unsigned int *send_only); | 280 | unsigned int *send_only); |
281 | |||
282 | struct ipoib_path_iter *ipoib_path_iter_init(struct net_device *dev); | ||
283 | int ipoib_path_iter_next(struct ipoib_path_iter *iter); | ||
284 | void ipoib_path_iter_read(struct ipoib_path_iter *iter, | ||
285 | struct ipoib_path *path); | ||
281 | #endif | 286 | #endif |
282 | 287 | ||
283 | int ipoib_mcast_attach(struct net_device *dev, u16 mlid, | 288 | int ipoib_mcast_attach(struct net_device *dev, u16 mlid, |
@@ -299,13 +304,13 @@ void ipoib_pkey_poll(void *dev); | |||
299 | int ipoib_pkey_dev_delay_open(struct net_device *dev); | 304 | int ipoib_pkey_dev_delay_open(struct net_device *dev); |
300 | 305 | ||
301 | #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG | 306 | #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG |
302 | int ipoib_create_debug_file(struct net_device *dev); | 307 | void ipoib_create_debug_files(struct net_device *dev); |
303 | void ipoib_delete_debug_file(struct net_device *dev); | 308 | void ipoib_delete_debug_files(struct net_device *dev); |
304 | int ipoib_register_debugfs(void); | 309 | int ipoib_register_debugfs(void); |
305 | void ipoib_unregister_debugfs(void); | 310 | void ipoib_unregister_debugfs(void); |
306 | #else | 311 | #else |
307 | static inline int ipoib_create_debug_file(struct net_device *dev) { return 0; } | 312 | static inline void ipoib_create_debug_files(struct net_device *dev) { } |
308 | static inline void ipoib_delete_debug_file(struct net_device *dev) { } | 313 | static inline void ipoib_delete_debug_files(struct net_device *dev) { } |
309 | static inline int ipoib_register_debugfs(void) { return 0; } | 314 | static inline int ipoib_register_debugfs(void) { return 0; } |
310 | static inline void ipoib_unregister_debugfs(void) { } | 315 | static inline void ipoib_unregister_debugfs(void) { } |
311 | #endif | 316 | #endif |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_fs.c b/drivers/infiniband/ulp/ipoib/ipoib_fs.c index 38b150f775e7..685258e34034 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_fs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_fs.c | |||
@@ -43,6 +43,18 @@ struct file_operations; | |||
43 | 43 | ||
44 | static struct dentry *ipoib_root; | 44 | static struct dentry *ipoib_root; |
45 | 45 | ||
46 | static void format_gid(union ib_gid *gid, char *buf) | ||
47 | { | ||
48 | int i, n; | ||
49 | |||
50 | for (n = 0, i = 0; i < 8; ++i) { | ||
51 | n += sprintf(buf + n, "%x", | ||
52 | be16_to_cpu(((__be16 *) gid->raw)[i])); | ||
53 | if (i < 7) | ||
54 | buf[n++] = ':'; | ||
55 | } | ||
56 | } | ||
57 | |||
46 | static void *ipoib_mcg_seq_start(struct seq_file *file, loff_t *pos) | 58 | static void *ipoib_mcg_seq_start(struct seq_file *file, loff_t *pos) |
47 | { | 59 | { |
48 | struct ipoib_mcast_iter *iter; | 60 | struct ipoib_mcast_iter *iter; |
@@ -54,7 +66,7 @@ static void *ipoib_mcg_seq_start(struct seq_file *file, loff_t *pos) | |||
54 | 66 | ||
55 | while (n--) { | 67 | while (n--) { |
56 | if (ipoib_mcast_iter_next(iter)) { | 68 | if (ipoib_mcast_iter_next(iter)) { |
57 | ipoib_mcast_iter_free(iter); | 69 | kfree(iter); |
58 | return NULL; | 70 | return NULL; |
59 | } | 71 | } |
60 | } | 72 | } |
@@ -70,7 +82,7 @@ static void *ipoib_mcg_seq_next(struct seq_file *file, void *iter_ptr, | |||
70 | (*pos)++; | 82 | (*pos)++; |
71 | 83 | ||
72 | if (ipoib_mcast_iter_next(iter)) { | 84 | if (ipoib_mcast_iter_next(iter)) { |
73 | ipoib_mcast_iter_free(iter); | 85 | kfree(iter); |
74 | return NULL; | 86 | return NULL; |
75 | } | 87 | } |
76 | 88 | ||
@@ -87,32 +99,32 @@ static int ipoib_mcg_seq_show(struct seq_file *file, void *iter_ptr) | |||
87 | struct ipoib_mcast_iter *iter = iter_ptr; | 99 | struct ipoib_mcast_iter *iter = iter_ptr; |
88 | char gid_buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"]; | 100 | char gid_buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"]; |
89 | union ib_gid mgid; | 101 | union ib_gid mgid; |
90 | int i, n; | ||
91 | unsigned long created; | 102 | unsigned long created; |
92 | unsigned int queuelen, complete, send_only; | 103 | unsigned int queuelen, complete, send_only; |
93 | 104 | ||
94 | if (iter) { | 105 | if (!iter) |
95 | ipoib_mcast_iter_read(iter, &mgid, &created, &queuelen, | 106 | return 0; |
96 | &complete, &send_only); | ||
97 | 107 | ||
98 | for (n = 0, i = 0; i < sizeof mgid / 2; ++i) { | 108 | ipoib_mcast_iter_read(iter, &mgid, &created, &queuelen, |
99 | n += sprintf(gid_buf + n, "%x", | 109 | &complete, &send_only); |
100 | be16_to_cpu(((__be16 *) mgid.raw)[i])); | ||
101 | if (i < sizeof mgid / 2 - 1) | ||
102 | gid_buf[n++] = ':'; | ||
103 | } | ||
104 | } | ||
105 | 110 | ||
106 | seq_printf(file, "GID: %*s", -(1 + (int) sizeof gid_buf), gid_buf); | 111 | format_gid(&mgid, gid_buf); |
107 | 112 | ||
108 | seq_printf(file, | 113 | seq_printf(file, |
109 | " created: %10ld queuelen: %4d complete: %d send_only: %d\n", | 114 | "GID: %s\n" |
110 | created, queuelen, complete, send_only); | 115 | " created: %10ld\n" |
116 | " queuelen: %9d\n" | ||
117 | " complete: %9s\n" | ||
118 | " send_only: %8s\n" | ||
119 | "\n", | ||
120 | gid_buf, created, queuelen, | ||
121 | complete ? "yes" : "no", | ||
122 | send_only ? "yes" : "no"); | ||
111 | 123 | ||
112 | return 0; | 124 | return 0; |
113 | } | 125 | } |
114 | 126 | ||
115 | static struct seq_operations ipoib_seq_ops = { | 127 | static struct seq_operations ipoib_mcg_seq_ops = { |
116 | .start = ipoib_mcg_seq_start, | 128 | .start = ipoib_mcg_seq_start, |
117 | .next = ipoib_mcg_seq_next, | 129 | .next = ipoib_mcg_seq_next, |
118 | .stop = ipoib_mcg_seq_stop, | 130 | .stop = ipoib_mcg_seq_stop, |
@@ -124,7 +136,7 @@ static int ipoib_mcg_open(struct inode *inode, struct file *file) | |||
124 | struct seq_file *seq; | 136 | struct seq_file *seq; |
125 | int ret; | 137 | int ret; |
126 | 138 | ||
127 | ret = seq_open(file, &ipoib_seq_ops); | 139 | ret = seq_open(file, &ipoib_mcg_seq_ops); |
128 | if (ret) | 140 | if (ret) |
129 | return ret; | 141 | return ret; |
130 | 142 | ||
@@ -134,7 +146,7 @@ static int ipoib_mcg_open(struct inode *inode, struct file *file) | |||
134 | return 0; | 146 | return 0; |
135 | } | 147 | } |
136 | 148 | ||
137 | static struct file_operations ipoib_fops = { | 149 | static struct file_operations ipoib_mcg_fops = { |
138 | .owner = THIS_MODULE, | 150 | .owner = THIS_MODULE, |
139 | .open = ipoib_mcg_open, | 151 | .open = ipoib_mcg_open, |
140 | .read = seq_read, | 152 | .read = seq_read, |
@@ -142,25 +154,138 @@ static struct file_operations ipoib_fops = { | |||
142 | .release = seq_release | 154 | .release = seq_release |
143 | }; | 155 | }; |
144 | 156 | ||
145 | int ipoib_create_debug_file(struct net_device *dev) | 157 | static void *ipoib_path_seq_start(struct seq_file *file, loff_t *pos) |
158 | { | ||
159 | struct ipoib_path_iter *iter; | ||
160 | loff_t n = *pos; | ||
161 | |||
162 | iter = ipoib_path_iter_init(file->private); | ||
163 | if (!iter) | ||
164 | return NULL; | ||
165 | |||
166 | while (n--) { | ||
167 | if (ipoib_path_iter_next(iter)) { | ||
168 | kfree(iter); | ||
169 | return NULL; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | return iter; | ||
174 | } | ||
175 | |||
176 | static void *ipoib_path_seq_next(struct seq_file *file, void *iter_ptr, | ||
177 | loff_t *pos) | ||
178 | { | ||
179 | struct ipoib_path_iter *iter = iter_ptr; | ||
180 | |||
181 | (*pos)++; | ||
182 | |||
183 | if (ipoib_path_iter_next(iter)) { | ||
184 | kfree(iter); | ||
185 | return NULL; | ||
186 | } | ||
187 | |||
188 | return iter; | ||
189 | } | ||
190 | |||
191 | static void ipoib_path_seq_stop(struct seq_file *file, void *iter_ptr) | ||
192 | { | ||
193 | /* nothing for now */ | ||
194 | } | ||
195 | |||
196 | static int ipoib_path_seq_show(struct seq_file *file, void *iter_ptr) | ||
197 | { | ||
198 | struct ipoib_path_iter *iter = iter_ptr; | ||
199 | char gid_buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"]; | ||
200 | struct ipoib_path path; | ||
201 | int rate; | ||
202 | |||
203 | if (!iter) | ||
204 | return 0; | ||
205 | |||
206 | ipoib_path_iter_read(iter, &path); | ||
207 | |||
208 | format_gid(&path.pathrec.dgid, gid_buf); | ||
209 | |||
210 | seq_printf(file, | ||
211 | "GID: %s\n" | ||
212 | " complete: %6s\n", | ||
213 | gid_buf, path.pathrec.dlid ? "yes" : "no"); | ||
214 | |||
215 | if (path.pathrec.dlid) { | ||
216 | rate = ib_sa_rate_enum_to_int(path.pathrec.rate) * 25; | ||
217 | |||
218 | seq_printf(file, | ||
219 | " DLID: 0x%04x\n" | ||
220 | " SL: %12d\n" | ||
221 | " rate: %*d%s Gb/sec\n", | ||
222 | be16_to_cpu(path.pathrec.dlid), | ||
223 | path.pathrec.sl, | ||
224 | 10 - ((rate % 10) ? 2 : 0), | ||
225 | rate / 10, rate % 10 ? ".5" : ""); | ||
226 | } | ||
227 | |||
228 | seq_putc(file, '\n'); | ||
229 | |||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | static struct seq_operations ipoib_path_seq_ops = { | ||
234 | .start = ipoib_path_seq_start, | ||
235 | .next = ipoib_path_seq_next, | ||
236 | .stop = ipoib_path_seq_stop, | ||
237 | .show = ipoib_path_seq_show, | ||
238 | }; | ||
239 | |||
240 | static int ipoib_path_open(struct inode *inode, struct file *file) | ||
241 | { | ||
242 | struct seq_file *seq; | ||
243 | int ret; | ||
244 | |||
245 | ret = seq_open(file, &ipoib_path_seq_ops); | ||
246 | if (ret) | ||
247 | return ret; | ||
248 | |||
249 | seq = file->private_data; | ||
250 | seq->private = inode->u.generic_ip; | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | static struct file_operations ipoib_path_fops = { | ||
256 | .owner = THIS_MODULE, | ||
257 | .open = ipoib_path_open, | ||
258 | .read = seq_read, | ||
259 | .llseek = seq_lseek, | ||
260 | .release = seq_release | ||
261 | }; | ||
262 | |||
263 | void ipoib_create_debug_files(struct net_device *dev) | ||
146 | { | 264 | { |
147 | struct ipoib_dev_priv *priv = netdev_priv(dev); | 265 | struct ipoib_dev_priv *priv = netdev_priv(dev); |
148 | char name[IFNAMSIZ + sizeof "_mcg"]; | 266 | char name[IFNAMSIZ + sizeof "_path"]; |
149 | 267 | ||
150 | snprintf(name, sizeof name, "%s_mcg", dev->name); | 268 | snprintf(name, sizeof name, "%s_mcg", dev->name); |
151 | |||
152 | priv->mcg_dentry = debugfs_create_file(name, S_IFREG | S_IRUGO, | 269 | priv->mcg_dentry = debugfs_create_file(name, S_IFREG | S_IRUGO, |
153 | ipoib_root, dev, &ipoib_fops); | 270 | ipoib_root, dev, &ipoib_mcg_fops); |
154 | 271 | if (!priv->mcg_dentry) | |
155 | return priv->mcg_dentry ? 0 : -ENOMEM; | 272 | ipoib_warn(priv, "failed to create mcg debug file\n"); |
273 | |||
274 | snprintf(name, sizeof name, "%s_path", dev->name); | ||
275 | priv->path_dentry = debugfs_create_file(name, S_IFREG | S_IRUGO, | ||
276 | ipoib_root, dev, &ipoib_path_fops); | ||
277 | if (!priv->path_dentry) | ||
278 | ipoib_warn(priv, "failed to create path debug file\n"); | ||
156 | } | 279 | } |
157 | 280 | ||
158 | void ipoib_delete_debug_file(struct net_device *dev) | 281 | void ipoib_delete_debug_files(struct net_device *dev) |
159 | { | 282 | { |
160 | struct ipoib_dev_priv *priv = netdev_priv(dev); | 283 | struct ipoib_dev_priv *priv = netdev_priv(dev); |
161 | 284 | ||
162 | if (priv->mcg_dentry) | 285 | if (priv->mcg_dentry) |
163 | debugfs_remove(priv->mcg_dentry); | 286 | debugfs_remove(priv->mcg_dentry); |
287 | if (priv->path_dentry) | ||
288 | debugfs_remove(priv->path_dentry); | ||
164 | } | 289 | } |
165 | 290 | ||
166 | int ipoib_register_debugfs(void) | 291 | int ipoib_register_debugfs(void) |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index ce0296273e76..2fa30751f362 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c | |||
@@ -58,6 +58,11 @@ module_param_named(debug_level, ipoib_debug_level, int, 0644); | |||
58 | MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0"); | 58 | MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0"); |
59 | #endif | 59 | #endif |
60 | 60 | ||
61 | struct ipoib_path_iter { | ||
62 | struct net_device *dev; | ||
63 | struct ipoib_path path; | ||
64 | }; | ||
65 | |||
61 | static const u8 ipv4_bcast_addr[] = { | 66 | static const u8 ipv4_bcast_addr[] = { |
62 | 0x00, 0xff, 0xff, 0xff, | 67 | 0x00, 0xff, 0xff, 0xff, |
63 | 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00, | 68 | 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00, |
@@ -250,6 +255,64 @@ static void path_free(struct net_device *dev, struct ipoib_path *path) | |||
250 | kfree(path); | 255 | kfree(path); |
251 | } | 256 | } |
252 | 257 | ||
258 | #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG | ||
259 | |||
260 | struct ipoib_path_iter *ipoib_path_iter_init(struct net_device *dev) | ||
261 | { | ||
262 | struct ipoib_path_iter *iter; | ||
263 | |||
264 | iter = kmalloc(sizeof *iter, GFP_KERNEL); | ||
265 | if (!iter) | ||
266 | return NULL; | ||
267 | |||
268 | iter->dev = dev; | ||
269 | memset(iter->path.pathrec.dgid.raw, 0, 16); | ||
270 | |||
271 | if (ipoib_path_iter_next(iter)) { | ||
272 | kfree(iter); | ||
273 | return NULL; | ||
274 | } | ||
275 | |||
276 | return iter; | ||
277 | } | ||
278 | |||
279 | int ipoib_path_iter_next(struct ipoib_path_iter *iter) | ||
280 | { | ||
281 | struct ipoib_dev_priv *priv = netdev_priv(iter->dev); | ||
282 | struct rb_node *n; | ||
283 | struct ipoib_path *path; | ||
284 | int ret = 1; | ||
285 | |||
286 | spin_lock_irq(&priv->lock); | ||
287 | |||
288 | n = rb_first(&priv->path_tree); | ||
289 | |||
290 | while (n) { | ||
291 | path = rb_entry(n, struct ipoib_path, rb_node); | ||
292 | |||
293 | if (memcmp(iter->path.pathrec.dgid.raw, path->pathrec.dgid.raw, | ||
294 | sizeof (union ib_gid)) < 0) { | ||
295 | iter->path = *path; | ||
296 | ret = 0; | ||
297 | break; | ||
298 | } | ||
299 | |||
300 | n = rb_next(n); | ||
301 | } | ||
302 | |||
303 | spin_unlock_irq(&priv->lock); | ||
304 | |||
305 | return ret; | ||
306 | } | ||
307 | |||
308 | void ipoib_path_iter_read(struct ipoib_path_iter *iter, | ||
309 | struct ipoib_path *path) | ||
310 | { | ||
311 | *path = iter->path; | ||
312 | } | ||
313 | |||
314 | #endif /* CONFIG_INFINIBAND_IPOIB_DEBUG */ | ||
315 | |||
253 | void ipoib_flush_paths(struct net_device *dev) | 316 | void ipoib_flush_paths(struct net_device *dev) |
254 | { | 317 | { |
255 | struct ipoib_dev_priv *priv = netdev_priv(dev); | 318 | struct ipoib_dev_priv *priv = netdev_priv(dev); |
@@ -763,7 +826,7 @@ void ipoib_dev_cleanup(struct net_device *dev) | |||
763 | { | 826 | { |
764 | struct ipoib_dev_priv *priv = netdev_priv(dev), *cpriv, *tcpriv; | 827 | struct ipoib_dev_priv *priv = netdev_priv(dev), *cpriv, *tcpriv; |
765 | 828 | ||
766 | ipoib_delete_debug_file(dev); | 829 | ipoib_delete_debug_files(dev); |
767 | 830 | ||
768 | /* Delete any child interfaces first */ | 831 | /* Delete any child interfaces first */ |
769 | list_for_each_entry_safe(cpriv, tcpriv, &priv->child_intfs, list) { | 832 | list_for_each_entry_safe(cpriv, tcpriv, &priv->child_intfs, list) { |
@@ -972,8 +1035,7 @@ static struct net_device *ipoib_add_port(const char *format, | |||
972 | goto register_failed; | 1035 | goto register_failed; |
973 | } | 1036 | } |
974 | 1037 | ||
975 | if (ipoib_create_debug_file(priv->dev)) | 1038 | ipoib_create_debug_files(priv->dev); |
976 | goto debug_failed; | ||
977 | 1039 | ||
978 | if (ipoib_add_pkey_attr(priv->dev)) | 1040 | if (ipoib_add_pkey_attr(priv->dev)) |
979 | goto sysfs_failed; | 1041 | goto sysfs_failed; |
@@ -987,9 +1049,7 @@ static struct net_device *ipoib_add_port(const char *format, | |||
987 | return priv->dev; | 1049 | return priv->dev; |
988 | 1050 | ||
989 | sysfs_failed: | 1051 | sysfs_failed: |
990 | ipoib_delete_debug_file(priv->dev); | 1052 | ipoib_delete_debug_files(priv->dev); |
991 | |||
992 | debug_failed: | ||
993 | unregister_netdev(priv->dev); | 1053 | unregister_netdev(priv->dev); |
994 | 1054 | ||
995 | register_failed: | 1055 | register_failed: |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 3ecf78a9493a..c33ed87f9dff 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c | |||
@@ -120,12 +120,8 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast) | |||
120 | if (mcast->ah) | 120 | if (mcast->ah) |
121 | ipoib_put_ah(mcast->ah); | 121 | ipoib_put_ah(mcast->ah); |
122 | 122 | ||
123 | while (!skb_queue_empty(&mcast->pkt_queue)) { | 123 | while (!skb_queue_empty(&mcast->pkt_queue)) |
124 | struct sk_buff *skb = skb_dequeue(&mcast->pkt_queue); | 124 | dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue)); |
125 | |||
126 | skb->dev = dev; | ||
127 | dev_kfree_skb_any(skb); | ||
128 | } | ||
129 | 125 | ||
130 | kfree(mcast); | 126 | kfree(mcast); |
131 | } | 127 | } |
@@ -317,13 +313,8 @@ ipoib_mcast_sendonly_join_complete(int status, | |||
317 | IPOIB_GID_ARG(mcast->mcmember.mgid), status); | 313 | IPOIB_GID_ARG(mcast->mcmember.mgid), status); |
318 | 314 | ||
319 | /* Flush out any queued packets */ | 315 | /* Flush out any queued packets */ |
320 | while (!skb_queue_empty(&mcast->pkt_queue)) { | 316 | while (!skb_queue_empty(&mcast->pkt_queue)) |
321 | struct sk_buff *skb = skb_dequeue(&mcast->pkt_queue); | 317 | dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue)); |
322 | |||
323 | skb->dev = dev; | ||
324 | |||
325 | dev_kfree_skb_any(skb); | ||
326 | } | ||
327 | 318 | ||
328 | /* Clear the busy flag so we try again */ | 319 | /* Clear the busy flag so we try again */ |
329 | clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); | 320 | clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); |
@@ -928,21 +919,16 @@ struct ipoib_mcast_iter *ipoib_mcast_iter_init(struct net_device *dev) | |||
928 | return NULL; | 919 | return NULL; |
929 | 920 | ||
930 | iter->dev = dev; | 921 | iter->dev = dev; |
931 | memset(iter->mgid.raw, 0, sizeof iter->mgid); | 922 | memset(iter->mgid.raw, 0, 16); |
932 | 923 | ||
933 | if (ipoib_mcast_iter_next(iter)) { | 924 | if (ipoib_mcast_iter_next(iter)) { |
934 | ipoib_mcast_iter_free(iter); | 925 | kfree(iter); |
935 | return NULL; | 926 | return NULL; |
936 | } | 927 | } |
937 | 928 | ||
938 | return iter; | 929 | return iter; |
939 | } | 930 | } |
940 | 931 | ||
941 | void ipoib_mcast_iter_free(struct ipoib_mcast_iter *iter) | ||
942 | { | ||
943 | kfree(iter); | ||
944 | } | ||
945 | |||
946 | int ipoib_mcast_iter_next(struct ipoib_mcast_iter *iter) | 932 | int ipoib_mcast_iter_next(struct ipoib_mcast_iter *iter) |
947 | { | 933 | { |
948 | struct ipoib_dev_priv *priv = netdev_priv(iter->dev); | 934 | struct ipoib_dev_priv *priv = netdev_priv(iter->dev); |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c index 332d730e60c2..d280b341a37f 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c | |||
@@ -113,8 +113,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) | |||
113 | 113 | ||
114 | priv->parent = ppriv->dev; | 114 | priv->parent = ppriv->dev; |
115 | 115 | ||
116 | if (ipoib_create_debug_file(priv->dev)) | 116 | ipoib_create_debug_files(priv->dev); |
117 | goto debug_failed; | ||
118 | 117 | ||
119 | if (ipoib_add_pkey_attr(priv->dev)) | 118 | if (ipoib_add_pkey_attr(priv->dev)) |
120 | goto sysfs_failed; | 119 | goto sysfs_failed; |
@@ -130,9 +129,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) | |||
130 | return 0; | 129 | return 0; |
131 | 130 | ||
132 | sysfs_failed: | 131 | sysfs_failed: |
133 | ipoib_delete_debug_file(priv->dev); | 132 | ipoib_delete_debug_files(priv->dev); |
134 | |||
135 | debug_failed: | ||
136 | unregister_netdev(priv->dev); | 133 | unregister_netdev(priv->dev); |
137 | 134 | ||
138 | register_failed: | 135 | register_failed: |
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 8f464271664d..49fa1e4413fa 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c | |||
@@ -2707,7 +2707,7 @@ bnx2_init_nvram(struct bnx2 *bp) | |||
2707 | 2707 | ||
2708 | if (j == entry_count) { | 2708 | if (j == entry_count) { |
2709 | bp->flash_info = NULL; | 2709 | bp->flash_info = NULL; |
2710 | printk(KERN_ALERT "Unknown flash/EEPROM type.\n"); | 2710 | printk(KERN_ALERT PFX "Unknown flash/EEPROM type.\n"); |
2711 | rc = -ENODEV; | 2711 | rc = -ENODEV; |
2712 | } | 2712 | } |
2713 | 2713 | ||
@@ -3903,6 +3903,8 @@ bnx2_test_loopback(struct bnx2 *bp) | |||
3903 | 3903 | ||
3904 | pkt_size = 1514; | 3904 | pkt_size = 1514; |
3905 | skb = dev_alloc_skb(pkt_size); | 3905 | skb = dev_alloc_skb(pkt_size); |
3906 | if (!skb) | ||
3907 | return -ENOMEM; | ||
3906 | packet = skb_put(skb, pkt_size); | 3908 | packet = skb_put(skb, pkt_size); |
3907 | memcpy(packet, bp->mac_addr, 6); | 3909 | memcpy(packet, bp->mac_addr, 6); |
3908 | memset(packet + 6, 0x0, 8); | 3910 | memset(packet + 6, 0x0, 8); |
@@ -4798,11 +4800,7 @@ bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, | |||
4798 | struct bnx2 *bp = dev->priv; | 4800 | struct bnx2 *bp = dev->priv; |
4799 | int rc; | 4801 | int rc; |
4800 | 4802 | ||
4801 | if (eeprom->offset > bp->flash_info->total_size) | 4803 | /* parameters already validated in ethtool_get_eeprom */ |
4802 | return -EINVAL; | ||
4803 | |||
4804 | if ((eeprom->offset + eeprom->len) > bp->flash_info->total_size) | ||
4805 | eeprom->len = bp->flash_info->total_size - eeprom->offset; | ||
4806 | 4804 | ||
4807 | rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len); | 4805 | rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len); |
4808 | 4806 | ||
@@ -4816,11 +4814,7 @@ bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, | |||
4816 | struct bnx2 *bp = dev->priv; | 4814 | struct bnx2 *bp = dev->priv; |
4817 | int rc; | 4815 | int rc; |
4818 | 4816 | ||
4819 | if (eeprom->offset > bp->flash_info->total_size) | 4817 | /* parameters already validated in ethtool_set_eeprom */ |
4820 | return -EINVAL; | ||
4821 | |||
4822 | if ((eeprom->offset + eeprom->len) > bp->flash_info->total_size) | ||
4823 | eeprom->len = bp->flash_info->total_size - eeprom->offset; | ||
4824 | 4818 | ||
4825 | rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len); | 4819 | rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len); |
4826 | 4820 | ||
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index 9342d5bc7bb4..f5d49a110654 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/ethtool.h> | 37 | #include <linux/ethtool.h> |
38 | #include <linux/bitops.h> | 38 | #include <linux/bitops.h> |
39 | #include <linux/fs.h> | 39 | #include <linux/fs.h> |
40 | #include <linux/platform_device.h> | ||
40 | 41 | ||
41 | #include <linux/vmalloc.h> | 42 | #include <linux/vmalloc.h> |
42 | #include <asm/pgtable.h> | 43 | #include <asm/pgtable.h> |
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c index a940b96433c7..e67b1d06611c 100644 --- a/drivers/net/fs_enet/mac-fcc.c +++ b/drivers/net/fs_enet/mac-fcc.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/ethtool.h> | 34 | #include <linux/ethtool.h> |
35 | #include <linux/bitops.h> | 35 | #include <linux/bitops.h> |
36 | #include <linux/fs.h> | 36 | #include <linux/fs.h> |
37 | #include <linux/platform_device.h> | ||
37 | 38 | ||
38 | #include <asm/immap_cpm2.h> | 39 | #include <asm/immap_cpm2.h> |
39 | #include <asm/mpc8260.h> | 40 | #include <asm/mpc8260.h> |
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c index 5ef4e845a387..2e8f44469699 100644 --- a/drivers/net/fs_enet/mac-fec.c +++ b/drivers/net/fs_enet/mac-fec.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/ethtool.h> | 34 | #include <linux/ethtool.h> |
35 | #include <linux/bitops.h> | 35 | #include <linux/bitops.h> |
36 | #include <linux/fs.h> | 36 | #include <linux/fs.h> |
37 | #include <linux/platform_device.h> | ||
37 | 38 | ||
38 | #include <asm/irq.h> | 39 | #include <asm/irq.h> |
39 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c index d8c6e9cadcf5..a3897fda71fa 100644 --- a/drivers/net/fs_enet/mac-scc.c +++ b/drivers/net/fs_enet/mac-scc.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/ethtool.h> | 34 | #include <linux/ethtool.h> |
35 | #include <linux/bitops.h> | 35 | #include <linux/bitops.h> |
36 | #include <linux/fs.h> | 36 | #include <linux/fs.h> |
37 | #include <linux/platform_device.h> | ||
37 | 38 | ||
38 | #include <asm/irq.h> | 39 | #include <asm/irq.h> |
39 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c index fcb66b9a0e28..e8593a60ee89 100644 --- a/drivers/pci/hotplug/rpadlpar_core.c +++ b/drivers/pci/hotplug/rpadlpar_core.c | |||
@@ -306,7 +306,7 @@ static int dlpar_add_phb(char *drc_name, struct device_node *dn) | |||
306 | { | 306 | { |
307 | struct pci_controller *phb; | 307 | struct pci_controller *phb; |
308 | 308 | ||
309 | if (PCI_DN(dn)->phb) { | 309 | if (PCI_DN(dn) && PCI_DN(dn)->phb) { |
310 | /* PHB already exists */ | 310 | /* PHB already exists */ |
311 | return -EINVAL; | 311 | return -EINVAL; |
312 | } | 312 | } |
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index ccf20039e909..309eb557f9a3 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig | |||
@@ -156,7 +156,7 @@ config TCIC | |||
156 | 156 | ||
157 | config PCMCIA_M8XX | 157 | config PCMCIA_M8XX |
158 | tristate "MPC8xx PCMCIA support" | 158 | tristate "MPC8xx PCMCIA support" |
159 | depends on PCMCIA && PPC | 159 | depends on PCMCIA && PPC && 8xx |
160 | select PCCARD_NONSTATIC | 160 | select PCCARD_NONSTATIC |
161 | help | 161 | help |
162 | Say Y here to include support for PowerPC 8xx series PCMCIA | 162 | Say Y here to include support for PowerPC 8xx series PCMCIA |
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index fe37541abbfe..bcecf5133b7e 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile | |||
@@ -25,7 +25,7 @@ obj-$(CONFIG_PD6729) += pd6729.o | |||
25 | obj-$(CONFIG_I82365) += i82365.o | 25 | obj-$(CONFIG_I82365) += i82365.o |
26 | obj-$(CONFIG_I82092) += i82092.o | 26 | obj-$(CONFIG_I82092) += i82092.o |
27 | obj-$(CONFIG_TCIC) += tcic.o | 27 | obj-$(CONFIG_TCIC) += tcic.o |
28 | obj-$(CONFIG_PCMCIA_M8XX) += m8xx_pcmcia.o | 28 | obj-$(CONFIG_PCMCIA_M8XX) += m8xx_pcmcia.o |
29 | obj-$(CONFIG_HD64465_PCMCIA) += hd64465_ss.o | 29 | obj-$(CONFIG_HD64465_PCMCIA) += hd64465_ss.o |
30 | obj-$(CONFIG_PCMCIA_SA1100) += sa11xx_core.o sa1100_cs.o | 30 | obj-$(CONFIG_PCMCIA_SA1100) += sa11xx_core.o sa1100_cs.o |
31 | obj-$(CONFIG_PCMCIA_SA1111) += sa11xx_core.o sa1111_cs.o | 31 | obj-$(CONFIG_PCMCIA_SA1111) += sa11xx_core.o sa1111_cs.o |
@@ -47,10 +47,10 @@ au1x00_ss-$(CONFIG_MIPS_PB1200) += au1000_db1x00.o | |||
47 | au1x00_ss-$(CONFIG_MIPS_PB1500) += au1000_pb1x00.o | 47 | au1x00_ss-$(CONFIG_MIPS_PB1500) += au1000_pb1x00.o |
48 | au1x00_ss-$(CONFIG_MIPS_DB1000) += au1000_db1x00.o | 48 | au1x00_ss-$(CONFIG_MIPS_DB1000) += au1000_db1x00.o |
49 | au1x00_ss-$(CONFIG_MIPS_DB1100) += au1000_db1x00.o | 49 | au1x00_ss-$(CONFIG_MIPS_DB1100) += au1000_db1x00.o |
50 | au1x00_ss-$(CONFIG_MIPS_DB1200) += au1000_db1x00.o | 50 | au1x00_ss-$(CONFIG_MIPS_DB1200) += au1000_db1x00.o |
51 | au1x00_ss-$(CONFIG_MIPS_DB1500) += au1000_db1x00.o | 51 | au1x00_ss-$(CONFIG_MIPS_DB1500) += au1000_db1x00.o |
52 | au1x00_ss-$(CONFIG_MIPS_DB1550) += au1000_db1x00.o | 52 | au1x00_ss-$(CONFIG_MIPS_DB1550) += au1000_db1x00.o |
53 | au1x00_ss-$(CONFIG_MIPS_XXS1500) += au1000_xxs1500.o | 53 | au1x00_ss-$(CONFIG_MIPS_XXS1500) += au1000_xxs1500.o |
54 | 54 | ||
55 | sa1111_cs-y += sa1111_generic.o | 55 | sa1111_cs-y += sa1111_generic.o |
56 | sa1111_cs-$(CONFIG_ASSABET_NEPONSET) += sa1100_neponset.o | 56 | sa1111_cs-$(CONFIG_ASSABET_NEPONSET) += sa1100_neponset.o |
diff --git a/drivers/pcmcia/au1000_db1x00.c b/drivers/pcmcia/au1000_db1x00.c index 24cfee1a412c..abc13f28ba3f 100644 --- a/drivers/pcmcia/au1000_db1x00.c +++ b/drivers/pcmcia/au1000_db1x00.c | |||
@@ -30,6 +30,7 @@ | |||
30 | * | 30 | * |
31 | */ | 31 | */ |
32 | 32 | ||
33 | #include <linux/config.h> | ||
33 | #include <linux/module.h> | 34 | #include <linux/module.h> |
34 | #include <linux/kernel.h> | 35 | #include <linux/kernel.h> |
35 | #include <linux/errno.h> | 36 | #include <linux/errno.h> |
diff --git a/drivers/pcmcia/au1000_generic.h b/drivers/pcmcia/au1000_generic.h index b0e7908392a7..f2c970b5f4ff 100644 --- a/drivers/pcmcia/au1000_generic.h +++ b/drivers/pcmcia/au1000_generic.h | |||
@@ -22,6 +22,8 @@ | |||
22 | #define __ASM_AU1000_PCMCIA_H | 22 | #define __ASM_AU1000_PCMCIA_H |
23 | 23 | ||
24 | /* include the world */ | 24 | /* include the world */ |
25 | #include <linux/config.h> | ||
26 | |||
25 | #include <pcmcia/cs_types.h> | 27 | #include <pcmcia/cs_types.h> |
26 | #include <pcmcia/cs.h> | 28 | #include <pcmcia/cs.h> |
27 | #include <pcmcia/ss.h> | 29 | #include <pcmcia/ss.h> |
diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c index 86c0808d6a05..fd5522ede867 100644 --- a/drivers/pcmcia/au1000_pb1x00.c +++ b/drivers/pcmcia/au1000_pb1x00.c | |||
@@ -21,6 +21,7 @@ | |||
21 | * with this program; if not, write to the Free Software Foundation, Inc., | 21 | * with this program; if not, write to the Free Software Foundation, Inc., |
22 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 22 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. |
23 | */ | 23 | */ |
24 | #include <linux/config.h> | ||
24 | #include <linux/module.h> | 25 | #include <linux/module.h> |
25 | #include <linux/init.h> | 26 | #include <linux/init.h> |
26 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
diff --git a/drivers/pcmcia/au1000_xxs1500.c b/drivers/pcmcia/au1000_xxs1500.c index 01a895bc9a47..01874b0bb03b 100644 --- a/drivers/pcmcia/au1000_xxs1500.c +++ b/drivers/pcmcia/au1000_xxs1500.c | |||
@@ -27,7 +27,6 @@ | |||
27 | */ | 27 | */ |
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/config.h> | ||
31 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
32 | #include <linux/ioport.h> | 31 | #include <linux/ioport.h> |
33 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index 7ce455d01cc9..4ddd76239b34 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c | |||
@@ -1366,6 +1366,7 @@ static int __init init_i82365(void) | |||
1366 | if (sockets == 0) { | 1366 | if (sockets == 0) { |
1367 | printk("not found.\n"); | 1367 | printk("not found.\n"); |
1368 | platform_device_unregister(&i82365_device); | 1368 | platform_device_unregister(&i82365_device); |
1369 | release_region(i365_base, 2); | ||
1369 | driver_unregister(&i82365_driver); | 1370 | driver_unregister(&i82365_driver); |
1370 | return -ENODEV; | 1371 | return -ENODEV; |
1371 | } | 1372 | } |
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c index f8bed87cf2f1..6d9f71cfcb34 100644 --- a/drivers/pcmcia/m8xx_pcmcia.c +++ b/drivers/pcmcia/m8xx_pcmcia.c | |||
@@ -39,7 +39,6 @@ | |||
39 | 39 | ||
40 | #include <asm/io.h> | 40 | #include <asm/io.h> |
41 | #include <asm/bitops.h> | 41 | #include <asm/bitops.h> |
42 | #include <asm/segment.h> | ||
43 | #include <asm/system.h> | 42 | #include <asm/system.h> |
44 | 43 | ||
45 | #include <linux/kernel.h> | 44 | #include <linux/kernel.h> |
@@ -50,6 +49,7 @@ | |||
50 | #include <linux/ioport.h> | 49 | #include <linux/ioport.h> |
51 | #include <linux/delay.h> | 50 | #include <linux/delay.h> |
52 | #include <linux/interrupt.h> | 51 | #include <linux/interrupt.h> |
52 | #include <linux/platform_device.h> | ||
53 | 53 | ||
54 | #include <asm/mpc8xx.h> | 54 | #include <asm/mpc8xx.h> |
55 | #include <asm/8xx_immap.h> | 55 | #include <asm/8xx_immap.h> |
@@ -546,29 +546,11 @@ static void m8xx_shutdown(void) | |||
546 | free_irq(pcmcia_schlvl, NULL); | 546 | free_irq(pcmcia_schlvl, NULL); |
547 | } | 547 | } |
548 | 548 | ||
549 | /* copied from tcic.c */ | ||
550 | |||
551 | static int m8xx_drv_suspend(struct device *dev, pm_message_t state, u32 level) | ||
552 | { | ||
553 | int ret = 0; | ||
554 | if (level == SUSPEND_SAVE_STATE) | ||
555 | ret = pcmcia_socket_dev_suspend(dev, state); | ||
556 | return ret; | ||
557 | } | ||
558 | |||
559 | static int m8xx_drv_resume(struct device *dev, u32 level) | ||
560 | { | ||
561 | int ret = 0; | ||
562 | if (level == RESUME_RESTORE_STATE) | ||
563 | ret = pcmcia_socket_dev_resume(dev); | ||
564 | return ret; | ||
565 | } | ||
566 | |||
567 | static struct device_driver m8xx_driver = { | 549 | static struct device_driver m8xx_driver = { |
568 | .name = "m8xx-pcmcia", | 550 | .name = "m8xx-pcmcia", |
569 | .bus = &platform_bus_type, | 551 | .bus = &platform_bus_type, |
570 | .suspend = m8xx_drv_suspend, | 552 | .suspend = pcmcia_socket_dev_suspend, |
571 | .resume = m8xx_drv_resume, | 553 | .resume = pcmcia_socket_dev_resume, |
572 | }; | 554 | }; |
573 | 555 | ||
574 | static struct platform_device m8xx_device = { | 556 | static struct platform_device m8xx_device = { |
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index c888af4a4562..3553da0e1cd5 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c | |||
@@ -395,6 +395,7 @@ static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs) | |||
395 | int log = test_bit(IDESCSI_LOG_CMD, &scsi->log); | 395 | int log = test_bit(IDESCSI_LOG_CMD, &scsi->log); |
396 | struct Scsi_Host *host; | 396 | struct Scsi_Host *host; |
397 | u8 *scsi_buf; | 397 | u8 *scsi_buf; |
398 | int errors = rq->errors; | ||
398 | unsigned long flags; | 399 | unsigned long flags; |
399 | 400 | ||
400 | if (!(rq->flags & (REQ_SPECIAL|REQ_SENSE))) { | 401 | if (!(rq->flags & (REQ_SPECIAL|REQ_SENSE))) { |
@@ -421,11 +422,11 @@ static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs) | |||
421 | printk (KERN_WARNING "ide-scsi: %s: timed out for %lu\n", | 422 | printk (KERN_WARNING "ide-scsi: %s: timed out for %lu\n", |
422 | drive->name, pc->scsi_cmd->serial_number); | 423 | drive->name, pc->scsi_cmd->serial_number); |
423 | pc->scsi_cmd->result = DID_TIME_OUT << 16; | 424 | pc->scsi_cmd->result = DID_TIME_OUT << 16; |
424 | } else if (rq->errors >= ERROR_MAX) { | 425 | } else if (errors >= ERROR_MAX) { |
425 | pc->scsi_cmd->result = DID_ERROR << 16; | 426 | pc->scsi_cmd->result = DID_ERROR << 16; |
426 | if (log) | 427 | if (log) |
427 | printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number); | 428 | printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number); |
428 | } else if (rq->errors) { | 429 | } else if (errors) { |
429 | if (log) | 430 | if (log) |
430 | printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number); | 431 | printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number); |
431 | if (!idescsi_check_condition(drive, rq)) | 432 | if (!idescsi_check_condition(drive, rq)) |
diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c index 4867498f68e8..bd9a6996aee7 100644 --- a/drivers/video/backlight/corgi_bl.c +++ b/drivers/video/backlight/corgi_bl.c | |||
@@ -48,6 +48,12 @@ static void corgibl_send_intensity(int intensity) | |||
48 | corgibl_mach_set_intensity(intensity); | 48 | corgibl_mach_set_intensity(intensity); |
49 | 49 | ||
50 | spin_unlock_irqrestore(&bl_lock, flags); | 50 | spin_unlock_irqrestore(&bl_lock, flags); |
51 | |||
52 | corgi_kick_batt = symbol_get(sharpsl_battery_kick); | ||
53 | if (corgi_kick_batt) { | ||
54 | corgi_kick_batt(); | ||
55 | symbol_put(sharpsl_battery_kick); | ||
56 | } | ||
51 | } | 57 | } |
52 | 58 | ||
53 | static void corgibl_blank(int blank) | 59 | static void corgibl_blank(int blank) |
diff --git a/include/asm-alpha/ide.h b/include/asm-alpha/ide.h index 68934a25931f..6126afe27380 100644 --- a/include/asm-alpha/ide.h +++ b/include/asm-alpha/ide.h | |||
@@ -15,10 +15,6 @@ | |||
15 | 15 | ||
16 | #include <linux/config.h> | 16 | #include <linux/config.h> |
17 | 17 | ||
18 | #ifndef MAX_HWIFS | ||
19 | #define MAX_HWIFS CONFIG_IDE_MAX_HWIFS | ||
20 | #endif | ||
21 | |||
22 | #define IDE_ARCH_OBSOLETE_DEFAULTS | 18 | #define IDE_ARCH_OBSOLETE_DEFAULTS |
23 | 19 | ||
24 | static inline int ide_default_irq(unsigned long base) | 20 | static inline int ide_default_irq(unsigned long base) |
diff --git a/include/asm-arm/arch-ixp4xx/hardware.h b/include/asm-arm/arch-ixp4xx/hardware.h index 55d85eea8c1a..cfb413c845f7 100644 --- a/include/asm-arm/arch-ixp4xx/hardware.h +++ b/include/asm-arm/arch-ixp4xx/hardware.h | |||
@@ -44,5 +44,6 @@ extern unsigned int processor_id; | |||
44 | #include "ixdp425.h" | 44 | #include "ixdp425.h" |
45 | #include "coyote.h" | 45 | #include "coyote.h" |
46 | #include "prpmc1100.h" | 46 | #include "prpmc1100.h" |
47 | #include "nslu2.h" | ||
47 | 48 | ||
48 | #endif /* _ASM_ARCH_HARDWARE_H */ | 49 | #endif /* _ASM_ARCH_HARDWARE_H */ |
diff --git a/include/asm-arm/arch-ixp4xx/irqs.h b/include/asm-arm/arch-ixp4xx/irqs.h index ca808281c7f9..2cf4930372bc 100644 --- a/include/asm-arm/arch-ixp4xx/irqs.h +++ b/include/asm-arm/arch-ixp4xx/irqs.h | |||
@@ -93,4 +93,11 @@ | |||
93 | #define IRQ_COYOTE_PCI_SLOT1 IRQ_IXP4XX_GPIO11 | 93 | #define IRQ_COYOTE_PCI_SLOT1 IRQ_IXP4XX_GPIO11 |
94 | #define IRQ_COYOTE_IDE IRQ_IXP4XX_GPIO5 | 94 | #define IRQ_COYOTE_IDE IRQ_IXP4XX_GPIO5 |
95 | 95 | ||
96 | /* | ||
97 | * NSLU2 board IRQs | ||
98 | */ | ||
99 | #define IRQ_NSLU2_PCI_INTA IRQ_IXP4XX_GPIO11 | ||
100 | #define IRQ_NSLU2_PCI_INTB IRQ_IXP4XX_GPIO10 | ||
101 | #define IRQ_NSLU2_PCI_INTC IRQ_IXP4XX_GPIO9 | ||
102 | |||
96 | #endif | 103 | #endif |
diff --git a/include/asm-arm/arch-ixp4xx/nslu2.h b/include/asm-arm/arch-ixp4xx/nslu2.h new file mode 100644 index 000000000000..b8b347a559c7 --- /dev/null +++ b/include/asm-arm/arch-ixp4xx/nslu2.h | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * include/asm-arm/arch-ixp4xx/nslu2.h | ||
3 | * | ||
4 | * NSLU2 platform specific definitions | ||
5 | * | ||
6 | * Author: Mark Rakes <mrakes AT mac.com> | ||
7 | * Maintainers: http://www.nslu2-linux.org | ||
8 | * | ||
9 | * based on ixdp425.h: | ||
10 | * Copyright 2004 (c) MontaVista, Software, Inc. | ||
11 | * | ||
12 | * This file is licensed under the terms of the GNU General Public | ||
13 | * License version 2. This program is licensed "as is" without any | ||
14 | * warranty of any kind, whether express or implied. | ||
15 | */ | ||
16 | |||
17 | #ifndef __ASM_ARCH_HARDWARE_H__ | ||
18 | #error "Do not include this directly, instead #include <asm/hardware.h>" | ||
19 | #endif | ||
20 | |||
21 | #define NSLU2_FLASH_BASE IXP4XX_EXP_BUS_CS0_BASE_PHYS | ||
22 | #define NSLU2_FLASH_SIZE IXP4XX_EXP_BUS_CSX_REGION_SIZE | ||
23 | |||
24 | #define NSLU2_SDA_PIN 7 | ||
25 | #define NSLU2_SCL_PIN 6 | ||
26 | |||
27 | /* | ||
28 | * NSLU2 PCI IRQs | ||
29 | */ | ||
30 | #define NSLU2_PCI_MAX_DEV 3 | ||
31 | #define NSLU2_PCI_IRQ_LINES 3 | ||
32 | |||
33 | |||
34 | /* PCI controller GPIO to IRQ pin mappings */ | ||
35 | #define NSLU2_PCI_INTA_PIN 11 | ||
36 | #define NSLU2_PCI_INTB_PIN 10 | ||
37 | #define NSLU2_PCI_INTC_PIN 9 | ||
38 | #define NSLU2_PCI_INTD_PIN 8 | ||
39 | |||
40 | |||
41 | /* NSLU2 Timer */ | ||
42 | #define NSLU2_FREQ 66000000 | ||
43 | #define NSLU2_CLOCK_TICK_RATE (((NSLU2_FREQ / HZ & ~IXP4XX_OST_RELOAD_MASK) + 1) * HZ) | ||
44 | #define NSLU2_CLOCK_TICKS_PER_USEC ((NSLU2_CLOCK_TICK_RATE + USEC_PER_SEC/2) / USEC_PER_SEC) | ||
45 | |||
46 | /* GPIO */ | ||
47 | |||
48 | #define NSLU2_GPIO0 0 | ||
49 | #define NSLU2_GPIO1 1 | ||
50 | #define NSLU2_GPIO2 2 | ||
51 | #define NSLU2_GPIO3 3 | ||
52 | #define NSLU2_GPIO4 4 | ||
53 | #define NSLU2_GPIO5 5 | ||
54 | #define NSLU2_GPIO6 6 | ||
55 | #define NSLU2_GPIO7 7 | ||
56 | #define NSLU2_GPIO8 8 | ||
57 | #define NSLU2_GPIO9 9 | ||
58 | #define NSLU2_GPIO10 10 | ||
59 | #define NSLU2_GPIO11 11 | ||
60 | #define NSLU2_GPIO12 12 | ||
61 | #define NSLU2_GPIO13 13 | ||
62 | #define NSLU2_GPIO14 14 | ||
63 | #define NSLU2_GPIO15 15 | ||
64 | |||
65 | /* Buttons */ | ||
66 | |||
67 | #define NSLU2_PB_GPIO NSLU2_GPIO5 | ||
68 | #define NSLU2_PO_GPIO NSLU2_GPIO8 /* power off */ | ||
69 | #define NSLU2_RB_GPIO NSLU2_GPIO12 | ||
70 | |||
71 | #define NSLU2_PB_IRQ IRQ_IXP4XX_GPIO5 | ||
72 | #define NSLU2_RB_IRQ IRQ_IXP4XX_GPIO12 | ||
73 | |||
74 | #define NSLU2_PB_BM (1L << NSLU2_PB_GPIO) | ||
75 | #define NSLU2_PO_BM (1L << NSLU2_PO_GPIO) | ||
76 | #define NSLU2_RB_BM (1L << NSLU2_RB_GPIO) | ||
77 | |||
78 | /* Buzzer */ | ||
79 | |||
80 | #define NSLU2_GPIO_BUZZ 4 | ||
81 | #define NSLU2_BZ_BM (1L << NSLU2_GPIO_BUZZ) | ||
82 | /* LEDs */ | ||
83 | |||
84 | #define NSLU2_LED_RED NSLU2_GPIO0 | ||
85 | #define NSLU2_LED_GRN NSLU2_GPIO1 | ||
86 | |||
87 | #define NSLU2_LED_RED_BM (1L << NSLU2_LED_RED) | ||
88 | #define NSLU2_LED_GRN_BM (1L << NSLU2_LED_GRN) | ||
89 | |||
90 | #define NSLU2_LED_DISK1 NSLU2_GPIO2 | ||
91 | #define NSLU2_LED_DISK2 NSLU2_GPIO3 | ||
92 | |||
93 | #define NSLU2_LED_DISK1_BM (1L << NSLU2_GPIO2) | ||
94 | #define NSLU2_LED_DISK2_BM (1L << NSLU2_GPIO3) | ||
95 | |||
96 | |||
diff --git a/include/asm-arm/arch-omap/board-h4.h b/include/asm-arm/arch-omap/board-h4.h index d64ee9211eed..33ea29a41654 100644 --- a/include/asm-arm/arch-omap/board-h4.h +++ b/include/asm-arm/arch-omap/board-h4.h | |||
@@ -34,5 +34,11 @@ | |||
34 | #define OMAP24XX_ETHR_START 0x08000300 | 34 | #define OMAP24XX_ETHR_START 0x08000300 |
35 | #define OMAP24XX_ETHR_GPIO_IRQ 92 | 35 | #define OMAP24XX_ETHR_GPIO_IRQ 92 |
36 | 36 | ||
37 | #define H4_CS0_BASE 0x04000000 | ||
38 | |||
39 | #define H4_CS0_BASE 0x04000000 | ||
40 | |||
41 | #define H4_CS0_BASE 0x04000000 | ||
42 | |||
37 | #endif /* __ASM_ARCH_OMAP_H4_H */ | 43 | #endif /* __ASM_ARCH_OMAP_H4_H */ |
38 | 44 | ||
diff --git a/include/asm-arm/arch-omap/board-innovator.h b/include/asm-arm/arch-omap/board-innovator.h index 79574e0ed13d..b3cf33441f6e 100644 --- a/include/asm-arm/arch-omap/board-innovator.h +++ b/include/asm-arm/arch-omap/board-innovator.h | |||
@@ -26,7 +26,7 @@ | |||
26 | #ifndef __ASM_ARCH_OMAP_INNOVATOR_H | 26 | #ifndef __ASM_ARCH_OMAP_INNOVATOR_H |
27 | #define __ASM_ARCH_OMAP_INNOVATOR_H | 27 | #define __ASM_ARCH_OMAP_INNOVATOR_H |
28 | 28 | ||
29 | #if defined (CONFIG_ARCH_OMAP1510) | 29 | #if defined (CONFIG_ARCH_OMAP15XX) |
30 | 30 | ||
31 | #ifndef OMAP_SDRAM_DEVICE | 31 | #ifndef OMAP_SDRAM_DEVICE |
32 | #define OMAP_SDRAM_DEVICE D256M_1X16_4B | 32 | #define OMAP_SDRAM_DEVICE D256M_1X16_4B |
@@ -44,7 +44,7 @@ void fpga_write(unsigned char val, int reg); | |||
44 | unsigned char fpga_read(int reg); | 44 | unsigned char fpga_read(int reg); |
45 | #endif | 45 | #endif |
46 | 46 | ||
47 | #endif /* CONFIG_ARCH_OMAP1510 */ | 47 | #endif /* CONFIG_ARCH_OMAP15XX */ |
48 | 48 | ||
49 | #if defined (CONFIG_ARCH_OMAP16XX) | 49 | #if defined (CONFIG_ARCH_OMAP16XX) |
50 | 50 | ||
diff --git a/include/asm-arm/arch-omap/clock.h b/include/asm-arm/arch-omap/clock.h new file mode 100644 index 000000000000..740c297eb11c --- /dev/null +++ b/include/asm-arm/arch-omap/clock.h | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * linux/include/asm-arm/arch-omap/clock.h | ||
3 | * | ||
4 | * Copyright (C) 2004 - 2005 Nokia corporation | ||
5 | * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> | ||
6 | * Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, Inc | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef __ARCH_ARM_OMAP_CLOCK_H | ||
14 | #define __ARCH_ARM_OMAP_CLOCK_H | ||
15 | |||
16 | struct module; | ||
17 | |||
18 | struct clk { | ||
19 | struct list_head node; | ||
20 | struct module *owner; | ||
21 | const char *name; | ||
22 | struct clk *parent; | ||
23 | unsigned long rate; | ||
24 | __u32 flags; | ||
25 | void __iomem *enable_reg; | ||
26 | __u8 enable_bit; | ||
27 | __u8 rate_offset; | ||
28 | __u8 src_offset; | ||
29 | __s8 usecount; | ||
30 | void (*recalc)(struct clk *); | ||
31 | int (*set_rate)(struct clk *, unsigned long); | ||
32 | long (*round_rate)(struct clk *, unsigned long); | ||
33 | void (*init)(struct clk *); | ||
34 | int (*enable)(struct clk *); | ||
35 | void (*disable)(struct clk *); | ||
36 | }; | ||
37 | |||
38 | struct clk_functions { | ||
39 | int (*clk_enable)(struct clk *clk); | ||
40 | void (*clk_disable)(struct clk *clk); | ||
41 | int (*clk_use)(struct clk *clk); | ||
42 | void (*clk_unuse)(struct clk *clk); | ||
43 | long (*clk_round_rate)(struct clk *clk, unsigned long rate); | ||
44 | int (*clk_set_rate)(struct clk *clk, unsigned long rate); | ||
45 | int (*clk_set_parent)(struct clk *clk, struct clk *parent); | ||
46 | struct clk * (*clk_get_parent)(struct clk *clk); | ||
47 | void (*clk_allow_idle)(struct clk *clk); | ||
48 | void (*clk_deny_idle)(struct clk *clk); | ||
49 | }; | ||
50 | |||
51 | extern unsigned int mpurate; | ||
52 | extern struct list_head clocks; | ||
53 | extern spinlock_t clockfw_lock; | ||
54 | |||
55 | extern int clk_init(struct clk_functions * custom_clocks); | ||
56 | extern int clk_register(struct clk *clk); | ||
57 | extern void clk_unregister(struct clk *clk); | ||
58 | extern void propagate_rate(struct clk *clk); | ||
59 | extern void followparent_recalc(struct clk * clk); | ||
60 | extern void clk_allow_idle(struct clk *clk); | ||
61 | extern void clk_deny_idle(struct clk *clk); | ||
62 | |||
63 | /* Clock flags */ | ||
64 | #define RATE_CKCTL (1 << 0) /* Main fixed ratio clocks */ | ||
65 | #define RATE_FIXED (1 << 1) /* Fixed clock rate */ | ||
66 | #define RATE_PROPAGATES (1 << 2) /* Program children too */ | ||
67 | #define VIRTUAL_CLOCK (1 << 3) /* Composite clock from table */ | ||
68 | #define ALWAYS_ENABLED (1 << 4) /* Clock cannot be disabled */ | ||
69 | #define ENABLE_REG_32BIT (1 << 5) /* Use 32-bit access */ | ||
70 | #define VIRTUAL_IO_ADDRESS (1 << 6) /* Clock in virtual address */ | ||
71 | #define CLOCK_IDLE_CONTROL (1 << 7) | ||
72 | #define CLOCK_NO_IDLE_PARENT (1 << 8) | ||
73 | #define DELAYED_APP (1 << 9) /* Delay application of clock */ | ||
74 | #define CONFIG_PARTICIPANT (1 << 10) /* Fundamental clock */ | ||
75 | #define CM_MPU_SEL1 (1 << 11) /* Domain divider/source */ | ||
76 | #define CM_DSP_SEL1 (1 << 12) | ||
77 | #define CM_GFX_SEL1 (1 << 13) | ||
78 | #define CM_MODEM_SEL1 (1 << 14) | ||
79 | #define CM_CORE_SEL1 (1 << 15) /* Sets divider for many */ | ||
80 | #define CM_CORE_SEL2 (1 << 16) /* sets parent for GPT */ | ||
81 | #define CM_WKUP_SEL1 (1 << 17) | ||
82 | #define CM_PLL_SEL1 (1 << 18) | ||
83 | #define CM_PLL_SEL2 (1 << 19) | ||
84 | #define CM_SYSCLKOUT_SEL1 (1 << 20) | ||
85 | #define CLOCK_IN_OMAP730 (1 << 21) | ||
86 | #define CLOCK_IN_OMAP1510 (1 << 22) | ||
87 | #define CLOCK_IN_OMAP16XX (1 << 23) | ||
88 | #define CLOCK_IN_OMAP242X (1 << 24) | ||
89 | #define CLOCK_IN_OMAP243X (1 << 25) | ||
90 | |||
91 | #endif | ||
diff --git a/include/asm-arm/arch-omap/common.h b/include/asm-arm/arch-omap/common.h index 2a676b4f13b5..08d58abd8218 100644 --- a/include/asm-arm/arch-omap/common.h +++ b/include/asm-arm/arch-omap/common.h | |||
@@ -31,6 +31,6 @@ struct sys_timer; | |||
31 | 31 | ||
32 | extern void omap_map_common_io(void); | 32 | extern void omap_map_common_io(void); |
33 | extern struct sys_timer omap_timer; | 33 | extern struct sys_timer omap_timer; |
34 | extern void omap_serial_init(int ports[]); | 34 | extern void omap_serial_init(void); |
35 | 35 | ||
36 | #endif /* __ARCH_ARM_MACH_OMAP_COMMON_H */ | 36 | #endif /* __ARCH_ARM_MACH_OMAP_COMMON_H */ |
diff --git a/include/asm-arm/arch-omap/cpu.h b/include/asm-arm/arch-omap/cpu.h index 1119e2b53e72..ec7eb675d922 100644 --- a/include/asm-arm/arch-omap/cpu.h +++ b/include/asm-arm/arch-omap/cpu.h | |||
@@ -28,12 +28,7 @@ | |||
28 | 28 | ||
29 | extern unsigned int system_rev; | 29 | extern unsigned int system_rev; |
30 | 30 | ||
31 | #define OMAP_DIE_ID_0 0xfffe1800 | 31 | #define omap2_cpu_rev() ((system_rev >> 8) & 0x0f) |
32 | #define OMAP_DIE_ID_1 0xfffe1804 | ||
33 | #define OMAP_PRODUCTION_ID_0 0xfffe2000 | ||
34 | #define OMAP_PRODUCTION_ID_1 0xfffe2004 | ||
35 | #define OMAP32_ID_0 0xfffed400 | ||
36 | #define OMAP32_ID_1 0xfffed404 | ||
37 | 32 | ||
38 | /* | 33 | /* |
39 | * Test if multicore OMAP support is needed | 34 | * Test if multicore OMAP support is needed |
@@ -50,7 +45,7 @@ extern unsigned int system_rev; | |||
50 | # define OMAP_NAME omap730 | 45 | # define OMAP_NAME omap730 |
51 | # endif | 46 | # endif |
52 | #endif | 47 | #endif |
53 | #ifdef CONFIG_ARCH_OMAP1510 | 48 | #ifdef CONFIG_ARCH_OMAP15XX |
54 | # ifdef OMAP_NAME | 49 | # ifdef OMAP_NAME |
55 | # undef MULTI_OMAP1 | 50 | # undef MULTI_OMAP1 |
56 | # define MULTI_OMAP1 | 51 | # define MULTI_OMAP1 |
@@ -79,9 +74,11 @@ extern unsigned int system_rev; | |||
79 | * Macros to group OMAP into cpu classes. | 74 | * Macros to group OMAP into cpu classes. |
80 | * These can be used in most places. | 75 | * These can be used in most places. |
81 | * cpu_is_omap7xx(): True for OMAP730 | 76 | * cpu_is_omap7xx(): True for OMAP730 |
82 | * cpu_is_omap15xx(): True for OMAP1510 and OMAP5910 | 77 | * cpu_is_omap15xx(): True for OMAP1510, OMAP5910 and OMAP310 |
83 | * cpu_is_omap16xx(): True for OMAP1610, OMAP5912 and OMAP1710 | 78 | * cpu_is_omap16xx(): True for OMAP1610, OMAP5912 and OMAP1710 |
84 | * cpu_is_omap24xx(): True for OMAP2420 | 79 | * cpu_is_omap24xx(): True for OMAP2420, OMAP2422, OMAP2423, OMAP2430 |
80 | * cpu_is_omap242x(): True for OMAP2420, OMAP2422, OMAP2423 | ||
81 | * cpu_is_omap243x(): True for OMAP2430 | ||
85 | */ | 82 | */ |
86 | #define GET_OMAP_CLASS (system_rev & 0xff) | 83 | #define GET_OMAP_CLASS (system_rev & 0xff) |
87 | 84 | ||
@@ -91,22 +88,35 @@ static inline int is_omap ##class (void) \ | |||
91 | return (GET_OMAP_CLASS == (id)) ? 1 : 0; \ | 88 | return (GET_OMAP_CLASS == (id)) ? 1 : 0; \ |
92 | } | 89 | } |
93 | 90 | ||
91 | #define GET_OMAP_SUBCLASS ((system_rev >> 20) & 0x0fff) | ||
92 | |||
93 | #define IS_OMAP_SUBCLASS(subclass, id) \ | ||
94 | static inline int is_omap ##subclass (void) \ | ||
95 | { \ | ||
96 | return (GET_OMAP_SUBCLASS == (id)) ? 1 : 0; \ | ||
97 | } | ||
98 | |||
94 | IS_OMAP_CLASS(7xx, 0x07) | 99 | IS_OMAP_CLASS(7xx, 0x07) |
95 | IS_OMAP_CLASS(15xx, 0x15) | 100 | IS_OMAP_CLASS(15xx, 0x15) |
96 | IS_OMAP_CLASS(16xx, 0x16) | 101 | IS_OMAP_CLASS(16xx, 0x16) |
97 | IS_OMAP_CLASS(24xx, 0x24) | 102 | IS_OMAP_CLASS(24xx, 0x24) |
98 | 103 | ||
104 | IS_OMAP_SUBCLASS(242x, 0x242) | ||
105 | IS_OMAP_SUBCLASS(243x, 0x243) | ||
106 | |||
99 | #define cpu_is_omap7xx() 0 | 107 | #define cpu_is_omap7xx() 0 |
100 | #define cpu_is_omap15xx() 0 | 108 | #define cpu_is_omap15xx() 0 |
101 | #define cpu_is_omap16xx() 0 | 109 | #define cpu_is_omap16xx() 0 |
102 | #define cpu_is_omap24xx() 0 | 110 | #define cpu_is_omap24xx() 0 |
111 | #define cpu_is_omap242x() 0 | ||
112 | #define cpu_is_omap243x() 0 | ||
103 | 113 | ||
104 | #if defined(MULTI_OMAP1) | 114 | #if defined(MULTI_OMAP1) |
105 | # if defined(CONFIG_ARCH_OMAP730) | 115 | # if defined(CONFIG_ARCH_OMAP730) |
106 | # undef cpu_is_omap7xx | 116 | # undef cpu_is_omap7xx |
107 | # define cpu_is_omap7xx() is_omap7xx() | 117 | # define cpu_is_omap7xx() is_omap7xx() |
108 | # endif | 118 | # endif |
109 | # if defined(CONFIG_ARCH_OMAP1510) | 119 | # if defined(CONFIG_ARCH_OMAP15XX) |
110 | # undef cpu_is_omap15xx | 120 | # undef cpu_is_omap15xx |
111 | # define cpu_is_omap15xx() is_omap15xx() | 121 | # define cpu_is_omap15xx() is_omap15xx() |
112 | # endif | 122 | # endif |
@@ -119,7 +129,7 @@ IS_OMAP_CLASS(24xx, 0x24) | |||
119 | # undef cpu_is_omap7xx | 129 | # undef cpu_is_omap7xx |
120 | # define cpu_is_omap7xx() 1 | 130 | # define cpu_is_omap7xx() 1 |
121 | # endif | 131 | # endif |
122 | # if defined(CONFIG_ARCH_OMAP1510) | 132 | # if defined(CONFIG_ARCH_OMAP15XX) |
123 | # undef cpu_is_omap15xx | 133 | # undef cpu_is_omap15xx |
124 | # define cpu_is_omap15xx() 1 | 134 | # define cpu_is_omap15xx() 1 |
125 | # endif | 135 | # endif |
@@ -129,13 +139,18 @@ IS_OMAP_CLASS(24xx, 0x24) | |||
129 | # endif | 139 | # endif |
130 | # if defined(CONFIG_ARCH_OMAP24XX) | 140 | # if defined(CONFIG_ARCH_OMAP24XX) |
131 | # undef cpu_is_omap24xx | 141 | # undef cpu_is_omap24xx |
142 | # undef cpu_is_omap242x | ||
143 | # undef cpu_is_omap243x | ||
132 | # define cpu_is_omap24xx() 1 | 144 | # define cpu_is_omap24xx() 1 |
145 | # define cpu_is_omap242x() is_omap242x() | ||
146 | # define cpu_is_omap243x() is_omap243x() | ||
133 | # endif | 147 | # endif |
134 | #endif | 148 | #endif |
135 | 149 | ||
136 | /* | 150 | /* |
137 | * Macros to detect individual cpu types. | 151 | * Macros to detect individual cpu types. |
138 | * These are only rarely needed. | 152 | * These are only rarely needed. |
153 | * cpu_is_omap330(): True for OMAP330 | ||
139 | * cpu_is_omap730(): True for OMAP730 | 154 | * cpu_is_omap730(): True for OMAP730 |
140 | * cpu_is_omap1510(): True for OMAP1510 | 155 | * cpu_is_omap1510(): True for OMAP1510 |
141 | * cpu_is_omap1610(): True for OMAP1610 | 156 | * cpu_is_omap1610(): True for OMAP1610 |
@@ -144,6 +159,9 @@ IS_OMAP_CLASS(24xx, 0x24) | |||
144 | * cpu_is_omap1621(): True for OMAP1621 | 159 | * cpu_is_omap1621(): True for OMAP1621 |
145 | * cpu_is_omap1710(): True for OMAP1710 | 160 | * cpu_is_omap1710(): True for OMAP1710 |
146 | * cpu_is_omap2420(): True for OMAP2420 | 161 | * cpu_is_omap2420(): True for OMAP2420 |
162 | * cpu_is_omap2422(): True for OMAP2422 | ||
163 | * cpu_is_omap2423(): True for OMAP2423 | ||
164 | * cpu_is_omap2430(): True for OMAP2430 | ||
147 | */ | 165 | */ |
148 | #define GET_OMAP_TYPE ((system_rev >> 16) & 0xffff) | 166 | #define GET_OMAP_TYPE ((system_rev >> 16) & 0xffff) |
149 | 167 | ||
@@ -153,6 +171,7 @@ static inline int is_omap ##type (void) \ | |||
153 | return (GET_OMAP_TYPE == (id)) ? 1 : 0; \ | 171 | return (GET_OMAP_TYPE == (id)) ? 1 : 0; \ |
154 | } | 172 | } |
155 | 173 | ||
174 | IS_OMAP_TYPE(310, 0x0310) | ||
156 | IS_OMAP_TYPE(730, 0x0730) | 175 | IS_OMAP_TYPE(730, 0x0730) |
157 | IS_OMAP_TYPE(1510, 0x1510) | 176 | IS_OMAP_TYPE(1510, 0x1510) |
158 | IS_OMAP_TYPE(1610, 0x1610) | 177 | IS_OMAP_TYPE(1610, 0x1610) |
@@ -161,7 +180,11 @@ IS_OMAP_TYPE(5912, 0x1611) | |||
161 | IS_OMAP_TYPE(1621, 0x1621) | 180 | IS_OMAP_TYPE(1621, 0x1621) |
162 | IS_OMAP_TYPE(1710, 0x1710) | 181 | IS_OMAP_TYPE(1710, 0x1710) |
163 | IS_OMAP_TYPE(2420, 0x2420) | 182 | IS_OMAP_TYPE(2420, 0x2420) |
183 | IS_OMAP_TYPE(2422, 0x2422) | ||
184 | IS_OMAP_TYPE(2423, 0x2423) | ||
185 | IS_OMAP_TYPE(2430, 0x2430) | ||
164 | 186 | ||
187 | #define cpu_is_omap310() 0 | ||
165 | #define cpu_is_omap730() 0 | 188 | #define cpu_is_omap730() 0 |
166 | #define cpu_is_omap1510() 0 | 189 | #define cpu_is_omap1510() 0 |
167 | #define cpu_is_omap1610() 0 | 190 | #define cpu_is_omap1610() 0 |
@@ -170,31 +193,33 @@ IS_OMAP_TYPE(2420, 0x2420) | |||
170 | #define cpu_is_omap1621() 0 | 193 | #define cpu_is_omap1621() 0 |
171 | #define cpu_is_omap1710() 0 | 194 | #define cpu_is_omap1710() 0 |
172 | #define cpu_is_omap2420() 0 | 195 | #define cpu_is_omap2420() 0 |
196 | #define cpu_is_omap2422() 0 | ||
197 | #define cpu_is_omap2423() 0 | ||
198 | #define cpu_is_omap2430() 0 | ||
173 | 199 | ||
174 | #if defined(MULTI_OMAP1) | 200 | #if defined(MULTI_OMAP1) |
175 | # if defined(CONFIG_ARCH_OMAP730) | 201 | # if defined(CONFIG_ARCH_OMAP730) |
176 | # undef cpu_is_omap730 | 202 | # undef cpu_is_omap730 |
177 | # define cpu_is_omap730() is_omap730() | 203 | # define cpu_is_omap730() is_omap730() |
178 | # endif | 204 | # endif |
179 | # if defined(CONFIG_ARCH_OMAP1510) | ||
180 | # undef cpu_is_omap1510 | ||
181 | # define cpu_is_omap1510() is_omap1510() | ||
182 | # endif | ||
183 | #else | 205 | #else |
184 | # if defined(CONFIG_ARCH_OMAP730) | 206 | # if defined(CONFIG_ARCH_OMAP730) |
185 | # undef cpu_is_omap730 | 207 | # undef cpu_is_omap730 |
186 | # define cpu_is_omap730() 1 | 208 | # define cpu_is_omap730() 1 |
187 | # endif | 209 | # endif |
188 | # if defined(CONFIG_ARCH_OMAP1510) | ||
189 | # undef cpu_is_omap1510 | ||
190 | # define cpu_is_omap1510() 1 | ||
191 | # endif | ||
192 | #endif | 210 | #endif |
193 | 211 | ||
194 | /* | 212 | /* |
195 | * Whether we have MULTI_OMAP1 or not, we still need to distinguish | 213 | * Whether we have MULTI_OMAP1 or not, we still need to distinguish |
196 | * between 1611B/5912 and 1710. | 214 | * between 330 vs. 1510 and 1611B/5912 vs. 1710. |
197 | */ | 215 | */ |
216 | #if defined(CONFIG_ARCH_OMAP15XX) | ||
217 | # undef cpu_is_omap310 | ||
218 | # undef cpu_is_omap1510 | ||
219 | # define cpu_is_omap310() is_omap310() | ||
220 | # define cpu_is_omap1510() is_omap1510() | ||
221 | #endif | ||
222 | |||
198 | #if defined(CONFIG_ARCH_OMAP16XX) | 223 | #if defined(CONFIG_ARCH_OMAP16XX) |
199 | # undef cpu_is_omap1610 | 224 | # undef cpu_is_omap1610 |
200 | # undef cpu_is_omap1611 | 225 | # undef cpu_is_omap1611 |
@@ -208,9 +233,20 @@ IS_OMAP_TYPE(2420, 0x2420) | |||
208 | # define cpu_is_omap1710() is_omap1710() | 233 | # define cpu_is_omap1710() is_omap1710() |
209 | #endif | 234 | #endif |
210 | 235 | ||
211 | #if defined(CONFIG_ARCH_OMAP2420) | 236 | #if defined(CONFIG_ARCH_OMAP24XX) |
212 | # undef cpu_is_omap2420 | 237 | # undef cpu_is_omap2420 |
213 | # define cpu_is_omap2420() 1 | 238 | # undef cpu_is_omap2422 |
239 | # undef cpu_is_omap2423 | ||
240 | # undef cpu_is_omap2430 | ||
241 | # define cpu_is_omap2420() is_omap2420() | ||
242 | # define cpu_is_omap2422() is_omap2422() | ||
243 | # define cpu_is_omap2423() is_omap2423() | ||
244 | # define cpu_is_omap2430() is_omap2430() | ||
214 | #endif | 245 | #endif |
215 | 246 | ||
247 | /* Macros to detect if we have OMAP1 or OMAP2 */ | ||
248 | #define cpu_class_is_omap1() (cpu_is_omap730() || cpu_is_omap15xx() || \ | ||
249 | cpu_is_omap16xx()) | ||
250 | #define cpu_class_is_omap2() cpu_is_omap24xx() | ||
251 | |||
216 | #endif | 252 | #endif |
diff --git a/include/asm-arm/arch-omap/dma.h b/include/asm-arm/arch-omap/dma.h index 04ebef5c6e95..ccbcb580a5c1 100644 --- a/include/asm-arm/arch-omap/dma.h +++ b/include/asm-arm/arch-omap/dma.h | |||
@@ -22,9 +22,109 @@ | |||
22 | #define __ASM_ARCH_DMA_H | 22 | #define __ASM_ARCH_DMA_H |
23 | 23 | ||
24 | #define MAX_DMA_ADDRESS 0xffffffff | 24 | #define MAX_DMA_ADDRESS 0xffffffff |
25 | #define MAX_DMA_CHANNELS 0 | ||
26 | |||
27 | /* Hardware registers for omap1 */ | ||
28 | #define OMAP_DMA_BASE (0xfffed800) | ||
29 | #define OMAP_DMA_GCR (OMAP_DMA_BASE + 0x400) | ||
30 | #define OMAP_DMA_GSCR (OMAP_DMA_BASE + 0x404) | ||
31 | #define OMAP_DMA_GRST (OMAP_DMA_BASE + 0x408) | ||
32 | #define OMAP_DMA_HW_ID (OMAP_DMA_BASE + 0x442) | ||
33 | #define OMAP_DMA_PCH2_ID (OMAP_DMA_BASE + 0x444) | ||
34 | #define OMAP_DMA_PCH0_ID (OMAP_DMA_BASE + 0x446) | ||
35 | #define OMAP_DMA_PCH1_ID (OMAP_DMA_BASE + 0x448) | ||
36 | #define OMAP_DMA_PCHG_ID (OMAP_DMA_BASE + 0x44a) | ||
37 | #define OMAP_DMA_PCHD_ID (OMAP_DMA_BASE + 0x44c) | ||
38 | #define OMAP_DMA_CAPS_0_U (OMAP_DMA_BASE + 0x44e) | ||
39 | #define OMAP_DMA_CAPS_0_L (OMAP_DMA_BASE + 0x450) | ||
40 | #define OMAP_DMA_CAPS_1_U (OMAP_DMA_BASE + 0x452) | ||
41 | #define OMAP_DMA_CAPS_1_L (OMAP_DMA_BASE + 0x454) | ||
42 | #define OMAP_DMA_CAPS_2 (OMAP_DMA_BASE + 0x456) | ||
43 | #define OMAP_DMA_CAPS_3 (OMAP_DMA_BASE + 0x458) | ||
44 | #define OMAP_DMA_CAPS_4 (OMAP_DMA_BASE + 0x45a) | ||
45 | #define OMAP_DMA_PCH2_SR (OMAP_DMA_BASE + 0x460) | ||
46 | #define OMAP_DMA_PCH0_SR (OMAP_DMA_BASE + 0x480) | ||
47 | #define OMAP_DMA_PCH1_SR (OMAP_DMA_BASE + 0x482) | ||
48 | #define OMAP_DMA_PCHD_SR (OMAP_DMA_BASE + 0x4c0) | ||
49 | |||
50 | /* Hardware registers for omap2 */ | ||
51 | #define OMAP24XX_DMA_BASE (L4_24XX_BASE + 0x56000) | ||
52 | #define OMAP_DMA4_REVISION (OMAP24XX_DMA_BASE + 0x00) | ||
53 | #define OMAP_DMA4_GCR_REG (OMAP24XX_DMA_BASE + 0x78) | ||
54 | #define OMAP_DMA4_IRQSTATUS_L0 (OMAP24XX_DMA_BASE + 0x08) | ||
55 | #define OMAP_DMA4_IRQSTATUS_L1 (OMAP24XX_DMA_BASE + 0x0c) | ||
56 | #define OMAP_DMA4_IRQSTATUS_L2 (OMAP24XX_DMA_BASE + 0x10) | ||
57 | #define OMAP_DMA4_IRQSTATUS_L3 (OMAP24XX_DMA_BASE + 0x14) | ||
58 | #define OMAP_DMA4_IRQENABLE_L0 (OMAP24XX_DMA_BASE + 0x18) | ||
59 | #define OMAP_DMA4_IRQENABLE_L1 (OMAP24XX_DMA_BASE + 0x1c) | ||
60 | #define OMAP_DMA4_IRQENABLE_L2 (OMAP24XX_DMA_BASE + 0x20) | ||
61 | #define OMAP_DMA4_IRQENABLE_L3 (OMAP24XX_DMA_BASE + 0x24) | ||
62 | #define OMAP_DMA4_SYSSTATUS (OMAP24XX_DMA_BASE + 0x28) | ||
63 | #define OMAP_DMA4_CAPS_0 (OMAP24XX_DMA_BASE + 0x64) | ||
64 | #define OMAP_DMA4_CAPS_2 (OMAP24XX_DMA_BASE + 0x6c) | ||
65 | #define OMAP_DMA4_CAPS_3 (OMAP24XX_DMA_BASE + 0x70) | ||
66 | #define OMAP_DMA4_CAPS_4 (OMAP24XX_DMA_BASE + 0x74) | ||
67 | |||
68 | #ifdef CONFIG_ARCH_OMAP1 | ||
25 | 69 | ||
26 | #define OMAP_LOGICAL_DMA_CH_COUNT 17 | 70 | #define OMAP_LOGICAL_DMA_CH_COUNT 17 |
27 | 71 | ||
72 | /* Common channel specific registers for omap1 */ | ||
73 | #define OMAP_DMA_CSDP_REG(n) __REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x00) | ||
74 | #define OMAP_DMA_CCR_REG(n) __REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x02) | ||
75 | #define OMAP_DMA_CICR_REG(n) __REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x04) | ||
76 | #define OMAP_DMA_CSR_REG(n) __REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x06) | ||
77 | #define OMAP_DMA_CEN_REG(n) __REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x10) | ||
78 | #define OMAP_DMA_CFN_REG(n) __REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x12) | ||
79 | #define OMAP_DMA_CSFI_REG(n) __REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x14) | ||
80 | #define OMAP_DMA_CSEI_REG(n) __REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x16) | ||
81 | #define OMAP_DMA_CSAC_REG(n) __REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x18) | ||
82 | #define OMAP_DMA_CDAC_REG(n) __REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x1a) | ||
83 | #define OMAP_DMA_CDEI_REG(n) __REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x1c) | ||
84 | #define OMAP_DMA_CDFI_REG(n) __REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x1e) | ||
85 | #define OMAP_DMA_CLNK_CTRL_REG(n) __REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x28) | ||
86 | |||
87 | #else | ||
88 | |||
89 | #define OMAP_LOGICAL_DMA_CH_COUNT 32 /* REVISIT: Is this 32 + 2? */ | ||
90 | |||
91 | /* Common channel specific registers for omap2 */ | ||
92 | #define OMAP_DMA_CCR_REG(n) __REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0x80) | ||
93 | #define OMAP_DMA_CLNK_CTRL_REG(n) __REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0x84) | ||
94 | #define OMAP_DMA_CICR_REG(n) __REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0x88) | ||
95 | #define OMAP_DMA_CSR_REG(n) __REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0x8c) | ||
96 | #define OMAP_DMA_CSDP_REG(n) __REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0x90) | ||
97 | #define OMAP_DMA_CEN_REG(n) __REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0x94) | ||
98 | #define OMAP_DMA_CFN_REG(n) __REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0x98) | ||
99 | #define OMAP_DMA_CSEI_REG(n) __REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0xa4) | ||
100 | #define OMAP_DMA_CSFI_REG(n) __REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0xa8) | ||
101 | #define OMAP_DMA_CDEI_REG(n) __REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0xac) | ||
102 | #define OMAP_DMA_CDFI_REG(n) __REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0xb0) | ||
103 | #define OMAP_DMA_CSAC_REG(n) __REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0xb4) | ||
104 | #define OMAP_DMA_CDAC_REG(n) __REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0xb8) | ||
105 | |||
106 | #endif | ||
107 | |||
108 | /* Channel specific registers only on omap1 */ | ||
109 | #define OMAP1_DMA_CSSA_L_REG(n) __REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x08) | ||
110 | #define OMAP1_DMA_CSSA_U_REG(n) __REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x0a) | ||
111 | #define OMAP1_DMA_CDSA_L_REG(n) __REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x0c) | ||
112 | #define OMAP1_DMA_CDSA_U_REG(n) __REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x0e) | ||
113 | #define OMAP1_DMA_COLOR_L_REG(n) __REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x20) | ||
114 | #define OMAP1_DMA_CCR2_REG(n) __REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x24) | ||
115 | #define OMAP1_DMA_COLOR_U_REG(n) __REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x22) | ||
116 | #define OMAP1_DMA_LCH_CTRL_REG(n) __REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x2a) | ||
117 | |||
118 | /* Channel specific registers only on omap2 */ | ||
119 | #define OMAP2_DMA_CSSA_REG(n) __REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0x9c) | ||
120 | #define OMAP2_DMA_CDSA_REG(n) __REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0xa0) | ||
121 | #define OMAP2_DMA_CCEN_REG(n) __REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0xbc) | ||
122 | #define OMAP2_DMA_CCFN_REG(n) __REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0xc0) | ||
123 | #define OMAP2_DMA_COLOR_REG(n) __REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0xc4) | ||
124 | |||
125 | /*----------------------------------------------------------------------------*/ | ||
126 | |||
127 | /* DMA channels for omap1 */ | ||
28 | #define OMAP_DMA_NO_DEVICE 0 | 128 | #define OMAP_DMA_NO_DEVICE 0 |
29 | #define OMAP_DMA_MCSI1_TX 1 | 129 | #define OMAP_DMA_MCSI1_TX 1 |
30 | #define OMAP_DMA_MCSI1_RX 2 | 130 | #define OMAP_DMA_MCSI1_RX 2 |
@@ -85,29 +185,72 @@ | |||
85 | #define OMAP_DMA_MMC2_RX 55 | 185 | #define OMAP_DMA_MMC2_RX 55 |
86 | #define OMAP_DMA_CRYPTO_DES_OUT 56 | 186 | #define OMAP_DMA_CRYPTO_DES_OUT 56 |
87 | 187 | ||
188 | /* DMA channels for 24xx */ | ||
189 | #define OMAP24XX_DMA_NO_DEVICE 0 | ||
190 | #define OMAP24XX_DMA_XTI_DMA 1 /* S_DMA_0 */ | ||
191 | #define OMAP24XX_DMA_EXT_NDMA_REQ0 2 /* S_DMA_1 */ | ||
192 | #define OMAP24XX_DMA_EXT_NDMA_REQ1 3 /* S_DMA_2 */ | ||
193 | #define OMAP24XX_DMA_GPMC 4 /* S_DMA_3 */ | ||
194 | #define OMAP24XX_DMA_GFX 5 /* S_DMA_4 */ | ||
195 | #define OMAP24XX_DMA_DSS 6 /* S_DMA_5 */ | ||
196 | #define OMAP24XX_DMA_VLYNQ_TX 7 /* S_DMA_6 */ | ||
197 | #define OMAP24XX_DMA_CWT 8 /* S_DMA_7 */ | ||
198 | #define OMAP24XX_DMA_AES_TX 9 /* S_DMA_8 */ | ||
199 | #define OMAP24XX_DMA_AES_RX 10 /* S_DMA_9 */ | ||
200 | #define OMAP24XX_DMA_DES_TX 11 /* S_DMA_10 */ | ||
201 | #define OMAP24XX_DMA_DES_RX 12 /* S_DMA_11 */ | ||
202 | #define OMAP24XX_DMA_SHA1MD5_RX 13 /* S_DMA_12 */ | ||
88 | 203 | ||
89 | #define OMAP_DMA_BASE (0xfffed800) | 204 | #define OMAP24XX_DMA_EAC_AC_RD 17 /* S_DMA_16 */ |
90 | #define OMAP_DMA_GCR (OMAP_DMA_BASE + 0x400) | 205 | #define OMAP24XX_DMA_EAC_AC_WR 18 /* S_DMA_17 */ |
91 | #define OMAP_DMA_GSCR (OMAP_DMA_BASE + 0x404) | 206 | #define OMAP24XX_DMA_EAC_MD_UL_RD 19 /* S_DMA_18 */ |
92 | #define OMAP_DMA_GRST (OMAP_DMA_BASE + 0x408) | 207 | #define OMAP24XX_DMA_EAC_MD_UL_WR 20 /* S_DMA_19 */ |
93 | #define OMAP_DMA_HW_ID (OMAP_DMA_BASE + 0x442) | 208 | #define OMAP24XX_DMA_EAC_MD_DL_RD 21 /* S_DMA_20 */ |
94 | #define OMAP_DMA_PCH2_ID (OMAP_DMA_BASE + 0x444) | 209 | #define OMAP24XX_DMA_EAC_MD_DL_WR 22 /* S_DMA_21 */ |
95 | #define OMAP_DMA_PCH0_ID (OMAP_DMA_BASE + 0x446) | 210 | #define OMAP24XX_DMA_EAC_BT_UL_RD 23 /* S_DMA_22 */ |
96 | #define OMAP_DMA_PCH1_ID (OMAP_DMA_BASE + 0x448) | 211 | #define OMAP24XX_DMA_EAC_BT_UL_WR 24 /* S_DMA_23 */ |
97 | #define OMAP_DMA_PCHG_ID (OMAP_DMA_BASE + 0x44a) | 212 | #define OMAP24XX_DMA_EAC_BT_DL_RD 25 /* S_DMA_24 */ |
98 | #define OMAP_DMA_PCHD_ID (OMAP_DMA_BASE + 0x44c) | 213 | #define OMAP24XX_DMA_EAC_BT_DL_WR 26 /* S_DMA_25 */ |
99 | #define OMAP_DMA_CAPS_0_U (OMAP_DMA_BASE + 0x44e) | 214 | #define OMAP24XX_DMA_I2C1_TX 27 /* S_DMA_26 */ |
100 | #define OMAP_DMA_CAPS_0_L (OMAP_DMA_BASE + 0x450) | 215 | #define OMAP24XX_DMA_I2C1_RX 28 /* S_DMA_27 */ |
101 | #define OMAP_DMA_CAPS_1_U (OMAP_DMA_BASE + 0x452) | 216 | #define OMAP24XX_DMA_I2C2_TX 29 /* S_DMA_28 */ |
102 | #define OMAP_DMA_CAPS_1_L (OMAP_DMA_BASE + 0x454) | 217 | #define OMAP24XX_DMA_I2C2_RX 30 /* S_DMA_29 */ |
103 | #define OMAP_DMA_CAPS_2 (OMAP_DMA_BASE + 0x456) | 218 | #define OMAP24XX_DMA_MCBSP1_TX 31 /* SDMA_30 */ |
104 | #define OMAP_DMA_CAPS_3 (OMAP_DMA_BASE + 0x458) | 219 | #define OMAP24XX_DMA_MCBSP1_RX 32 /* SDMA_31 */ |
105 | #define OMAP_DMA_CAPS_4 (OMAP_DMA_BASE + 0x45a) | 220 | #define OMAP24XX_DMA_MCBSP2_TX 33 /* SDMA_32 */ |
106 | #define OMAP_DMA_PCH2_SR (OMAP_DMA_BASE + 0x460) | 221 | #define OMAP24XX_DMA_MCBSP2_RX 34 /* SDMA_33 */ |
107 | #define OMAP_DMA_PCH0_SR (OMAP_DMA_BASE + 0x480) | 222 | #define OMAP24XX_DMA_SPI1_TX0 35 /* SDMA_34 */ |
108 | #define OMAP_DMA_PCH1_SR (OMAP_DMA_BASE + 0x482) | 223 | #define OMAP24XX_DMA_SPI1_RX0 36 /* SDMA_35 */ |
109 | #define OMAP_DMA_PCHD_SR (OMAP_DMA_BASE + 0x4c0) | 224 | #define OMAP24XX_DMA_SPI1_TX1 37 /* SDMA_36 */ |
225 | #define OMAP24XX_DMA_SPI1_RX1 38 /* SDMA_37 */ | ||
226 | #define OMAP24XX_DMA_SPI1_TX2 39 /* SDMA_38 */ | ||
227 | #define OMAP24XX_DMA_SPI1_RX2 40 /* SDMA_39 */ | ||
228 | #define OMAP24XX_DMA_SPI1_TX3 41 /* SDMA_40 */ | ||
229 | #define OMAP24XX_DMA_SPI1_RX3 42 /* SDMA_41 */ | ||
230 | #define OMAP24XX_DMA_SPI2_TX0 43 /* SDMA_42 */ | ||
231 | #define OMAP24XX_DMA_SPI2_RX0 44 /* SDMA_43 */ | ||
232 | #define OMAP24XX_DMA_SPI2_TX1 45 /* SDMA_44 */ | ||
233 | #define OMAP24XX_DMA_SPI2_RX1 46 /* SDMA_45 */ | ||
110 | 234 | ||
235 | #define OMAP24XX_DMA_UART1_TX 49 /* SDMA_48 */ | ||
236 | #define OMAP24XX_DMA_UART1_RX 50 /* SDMA_49 */ | ||
237 | #define OMAP24XX_DMA_UART2_TX 51 /* SDMA_50 */ | ||
238 | #define OMAP24XX_DMA_UART2_RX 52 /* SDMA_51 */ | ||
239 | #define OMAP24XX_DMA_UART3_TX 53 /* SDMA_52 */ | ||
240 | #define OMAP24XX_DMA_UART3_RX 54 /* SDMA_53 */ | ||
241 | #define OMAP24XX_DMA_USB_W2FC_TX0 55 /* SDMA_54 */ | ||
242 | #define OMAP24XX_DMA_USB_W2FC_RX0 56 /* SDMA_55 */ | ||
243 | #define OMAP24XX_DMA_USB_W2FC_TX1 57 /* SDMA_56 */ | ||
244 | #define OMAP24XX_DMA_USB_W2FC_RX1 58 /* SDMA_57 */ | ||
245 | #define OMAP24XX_DMA_USB_W2FC_TX2 59 /* SDMA_58 */ | ||
246 | #define OMAP24XX_DMA_USB_W2FC_RX2 60 /* SDMA_59 */ | ||
247 | #define OMAP24XX_DMA_MMC1_TX 61 /* SDMA_60 */ | ||
248 | #define OMAP24XX_DMA_MMC1_RX 62 /* SDMA_61 */ | ||
249 | #define OMAP24XX_DMA_MS 63 /* SDMA_62 */ | ||
250 | |||
251 | /*----------------------------------------------------------------------------*/ | ||
252 | |||
253 | /* Hardware registers for LCD DMA */ | ||
111 | #define OMAP1510_DMA_LCD_BASE (0xfffedb00) | 254 | #define OMAP1510_DMA_LCD_BASE (0xfffedb00) |
112 | #define OMAP1510_DMA_LCD_CTRL (OMAP1510_DMA_LCD_BASE + 0x00) | 255 | #define OMAP1510_DMA_LCD_CTRL (OMAP1510_DMA_LCD_BASE + 0x00) |
113 | #define OMAP1510_DMA_LCD_TOP_F1_L (OMAP1510_DMA_LCD_BASE + 0x02) | 256 | #define OMAP1510_DMA_LCD_TOP_F1_L (OMAP1510_DMA_LCD_BASE + 0x02) |
@@ -116,7 +259,7 @@ | |||
116 | #define OMAP1510_DMA_LCD_BOT_F1_U (OMAP1510_DMA_LCD_BASE + 0x08) | 259 | #define OMAP1510_DMA_LCD_BOT_F1_U (OMAP1510_DMA_LCD_BASE + 0x08) |
117 | 260 | ||
118 | #define OMAP1610_DMA_LCD_BASE (0xfffee300) | 261 | #define OMAP1610_DMA_LCD_BASE (0xfffee300) |
119 | #define OMAP1610_DMA_LCD_CSDP (OMAP1610_DMA_LCD_BASE + 0xc0) | 262 | #define OMAP1610_DMA_LCD_CSDP (OMAP1610_DMA_LCD_BASE + 0xc0) |
120 | #define OMAP1610_DMA_LCD_CCR (OMAP1610_DMA_LCD_BASE + 0xc2) | 263 | #define OMAP1610_DMA_LCD_CCR (OMAP1610_DMA_LCD_BASE + 0xc2) |
121 | #define OMAP1610_DMA_LCD_CTRL (OMAP1610_DMA_LCD_BASE + 0xc4) | 264 | #define OMAP1610_DMA_LCD_CTRL (OMAP1610_DMA_LCD_BASE + 0xc4) |
122 | #define OMAP1610_DMA_LCD_TOP_B1_L (OMAP1610_DMA_LCD_BASE + 0xc8) | 265 | #define OMAP1610_DMA_LCD_TOP_B1_L (OMAP1610_DMA_LCD_BASE + 0xc8) |
@@ -134,37 +277,18 @@ | |||
134 | #define OMAP1610_DMA_LCD_LCH_CTRL (OMAP1610_DMA_LCD_BASE + 0xea) | 277 | #define OMAP1610_DMA_LCD_LCH_CTRL (OMAP1610_DMA_LCD_BASE + 0xea) |
135 | #define OMAP1610_DMA_LCD_SRC_FI_B1_U (OMAP1610_DMA_LCD_BASE + 0xf4) | 278 | #define OMAP1610_DMA_LCD_SRC_FI_B1_U (OMAP1610_DMA_LCD_BASE + 0xf4) |
136 | 279 | ||
137 | 280 | #define OMAP_DMA_TOUT_IRQ (1 << 0) /* Only on omap1 */ | |
138 | /* Every LCh has its own set of the registers below */ | ||
139 | #define OMAP_DMA_CSDP(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x00) | ||
140 | #define OMAP_DMA_CCR(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x02) | ||
141 | #define OMAP_DMA_CICR(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x04) | ||
142 | #define OMAP_DMA_CSR(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x06) | ||
143 | #define OMAP_DMA_CSSA_L(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x08) | ||
144 | #define OMAP_DMA_CSSA_U(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x0a) | ||
145 | #define OMAP_DMA_CDSA_L(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x0c) | ||
146 | #define OMAP_DMA_CDSA_U(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x0e) | ||
147 | #define OMAP_DMA_CEN(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x10) | ||
148 | #define OMAP_DMA_CFN(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x12) | ||
149 | #define OMAP_DMA_CSFI(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x14) | ||
150 | #define OMAP_DMA_CSEI(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x16) | ||
151 | #define OMAP_DMA_CSAC(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x18) | ||
152 | #define OMAP_DMA_CDAC(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x1a) | ||
153 | #define OMAP_DMA_CDEI(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x1c) | ||
154 | #define OMAP_DMA_CDFI(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x1e) | ||
155 | #define OMAP_DMA_COLOR_L(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x20) | ||
156 | #define OMAP_DMA_COLOR_U(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x22) | ||
157 | #define OMAP_DMA_CCR2(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x24) | ||
158 | #define OMAP_DMA_CLNK_CTRL(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x28) | ||
159 | #define OMAP_DMA_LCH_CTRL(n) (OMAP_DMA_BASE + 0x40 * (n) + 0x2a) | ||
160 | |||
161 | #define OMAP_DMA_TOUT_IRQ (1 << 0) | ||
162 | #define OMAP_DMA_DROP_IRQ (1 << 1) | 281 | #define OMAP_DMA_DROP_IRQ (1 << 1) |
163 | #define OMAP_DMA_HALF_IRQ (1 << 2) | 282 | #define OMAP_DMA_HALF_IRQ (1 << 2) |
164 | #define OMAP_DMA_FRAME_IRQ (1 << 3) | 283 | #define OMAP_DMA_FRAME_IRQ (1 << 3) |
165 | #define OMAP_DMA_LAST_IRQ (1 << 4) | 284 | #define OMAP_DMA_LAST_IRQ (1 << 4) |
166 | #define OMAP_DMA_BLOCK_IRQ (1 << 5) | 285 | #define OMAP_DMA_BLOCK_IRQ (1 << 5) |
167 | #define OMAP_DMA_SYNC_IRQ (1 << 6) | 286 | #define OMAP1_DMA_SYNC_IRQ (1 << 6) |
287 | #define OMAP2_DMA_PKT_IRQ (1 << 7) | ||
288 | #define OMAP2_DMA_TRANS_ERR_IRQ (1 << 8) | ||
289 | #define OMAP2_DMA_SECURE_ERR_IRQ (1 << 9) | ||
290 | #define OMAP2_DMA_SUPERVISOR_ERR_IRQ (1 << 10) | ||
291 | #define OMAP2_DMA_MISALIGNED_ERR_IRQ (1 << 11) | ||
168 | 292 | ||
169 | #define OMAP_DMA_DATA_TYPE_S8 0x00 | 293 | #define OMAP_DMA_DATA_TYPE_S8 0x00 |
170 | #define OMAP_DMA_DATA_TYPE_S16 0x01 | 294 | #define OMAP_DMA_DATA_TYPE_S16 0x01 |
@@ -194,6 +318,7 @@ enum { | |||
194 | OMAP_LCD_DMA_B2_BOTTOM | 318 | OMAP_LCD_DMA_B2_BOTTOM |
195 | }; | 319 | }; |
196 | 320 | ||
321 | /* REVISIT: Check if BURST_4 is really 1 (or 2) */ | ||
197 | enum omap_dma_burst_mode { | 322 | enum omap_dma_burst_mode { |
198 | OMAP_DMA_DATA_BURST_DIS = 0, | 323 | OMAP_DMA_DATA_BURST_DIS = 0, |
199 | OMAP_DMA_DATA_BURST_4, | 324 | OMAP_DMA_DATA_BURST_4, |
@@ -206,6 +331,31 @@ enum omap_dma_color_mode { | |||
206 | OMAP_DMA_TRANSPARENT_COPY | 331 | OMAP_DMA_TRANSPARENT_COPY |
207 | }; | 332 | }; |
208 | 333 | ||
334 | struct omap_dma_channel_params { | ||
335 | int data_type; /* data type 8,16,32 */ | ||
336 | int elem_count; /* number of elements in a frame */ | ||
337 | int frame_count; /* number of frames in a element */ | ||
338 | |||
339 | int src_port; /* Only on OMAP1 REVISIT: Is this needed? */ | ||
340 | int src_amode; /* constant , post increment, indexed , double indexed */ | ||
341 | int src_start; /* source address : physical */ | ||
342 | int src_ei; /* source element index */ | ||
343 | int src_fi; /* source frame index */ | ||
344 | |||
345 | int dst_port; /* Only on OMAP1 REVISIT: Is this needed? */ | ||
346 | int dst_amode; /* constant , post increment, indexed , double indexed */ | ||
347 | int dst_start; /* source address : physical */ | ||
348 | int dst_ei; /* source element index */ | ||
349 | int dst_fi; /* source frame index */ | ||
350 | |||
351 | int trigger; /* trigger attached if the channel is synchronized */ | ||
352 | int sync_mode; /* sycn on element, frame , block or packet */ | ||
353 | int src_or_dst_synch; /* source synch(1) or destination synch(0) */ | ||
354 | |||
355 | int ie; /* interrupt enabled */ | ||
356 | }; | ||
357 | |||
358 | |||
209 | extern void omap_set_dma_priority(int dst_port, int priority); | 359 | extern void omap_set_dma_priority(int dst_port, int priority); |
210 | extern int omap_request_dma(int dev_id, const char *dev_name, | 360 | extern int omap_request_dma(int dev_id, const char *dev_name, |
211 | void (* callback)(int lch, u16 ch_status, void *data), | 361 | void (* callback)(int lch, u16 ch_status, void *data), |
@@ -217,24 +367,30 @@ extern void omap_start_dma(int lch); | |||
217 | extern void omap_stop_dma(int lch); | 367 | extern void omap_stop_dma(int lch); |
218 | extern void omap_set_dma_transfer_params(int lch, int data_type, | 368 | extern void omap_set_dma_transfer_params(int lch, int data_type, |
219 | int elem_count, int frame_count, | 369 | int elem_count, int frame_count, |
220 | int sync_mode); | 370 | int sync_mode, |
371 | int dma_trigger, int src_or_dst_synch); | ||
221 | extern void omap_set_dma_color_mode(int lch, enum omap_dma_color_mode mode, | 372 | extern void omap_set_dma_color_mode(int lch, enum omap_dma_color_mode mode, |
222 | u32 color); | 373 | u32 color); |
223 | 374 | ||
224 | extern void omap_set_dma_src_params(int lch, int src_port, int src_amode, | 375 | extern void omap_set_dma_src_params(int lch, int src_port, int src_amode, |
225 | unsigned long src_start); | 376 | unsigned long src_start, |
377 | int src_ei, int src_fi); | ||
226 | extern void omap_set_dma_src_index(int lch, int eidx, int fidx); | 378 | extern void omap_set_dma_src_index(int lch, int eidx, int fidx); |
227 | extern void omap_set_dma_src_data_pack(int lch, int enable); | 379 | extern void omap_set_dma_src_data_pack(int lch, int enable); |
228 | extern void omap_set_dma_src_burst_mode(int lch, | 380 | extern void omap_set_dma_src_burst_mode(int lch, |
229 | enum omap_dma_burst_mode burst_mode); | 381 | enum omap_dma_burst_mode burst_mode); |
230 | 382 | ||
231 | extern void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode, | 383 | extern void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode, |
232 | unsigned long dest_start); | 384 | unsigned long dest_start, |
385 | int dst_ei, int dst_fi); | ||
233 | extern void omap_set_dma_dest_index(int lch, int eidx, int fidx); | 386 | extern void omap_set_dma_dest_index(int lch, int eidx, int fidx); |
234 | extern void omap_set_dma_dest_data_pack(int lch, int enable); | 387 | extern void omap_set_dma_dest_data_pack(int lch, int enable); |
235 | extern void omap_set_dma_dest_burst_mode(int lch, | 388 | extern void omap_set_dma_dest_burst_mode(int lch, |
236 | enum omap_dma_burst_mode burst_mode); | 389 | enum omap_dma_burst_mode burst_mode); |
237 | 390 | ||
391 | extern void omap_set_dma_params(int lch, | ||
392 | struct omap_dma_channel_params * params); | ||
393 | |||
238 | extern void omap_dma_link_lch (int lch_head, int lch_queue); | 394 | extern void omap_dma_link_lch (int lch_head, int lch_queue); |
239 | extern void omap_dma_unlink_lch (int lch_head, int lch_queue); | 395 | extern void omap_dma_unlink_lch (int lch_head, int lch_queue); |
240 | 396 | ||
@@ -244,9 +400,6 @@ extern int omap_get_dma_src_addr_counter(int lch); | |||
244 | extern void omap_clear_dma(int lch); | 400 | extern void omap_clear_dma(int lch); |
245 | extern int omap_dma_running(void); | 401 | extern int omap_dma_running(void); |
246 | 402 | ||
247 | /* Returns 1 if the DMA module is in OMAP1510-compatible mode, 0 otherwise */ | ||
248 | extern int omap_dma_in_1510_mode(void); | ||
249 | |||
250 | /* LCD DMA functions */ | 403 | /* LCD DMA functions */ |
251 | extern int omap_request_lcd_dma(void (* callback)(u16 status, void *data), | 404 | extern int omap_request_lcd_dma(void (* callback)(u16 status, void *data), |
252 | void *data); | 405 | void *data); |
diff --git a/include/asm-arm/arch-omap/entry-macro.S b/include/asm-arm/arch-omap/entry-macro.S index 0d29b9c56a95..f8814a84910e 100644 --- a/include/asm-arm/arch-omap/entry-macro.S +++ b/include/asm-arm/arch-omap/entry-macro.S | |||
@@ -10,6 +10,20 @@ | |||
10 | 10 | ||
11 | #if defined(CONFIG_ARCH_OMAP1) | 11 | #if defined(CONFIG_ARCH_OMAP1) |
12 | 12 | ||
13 | #if defined(CONFIG_ARCH_OMAP730) && \ | ||
14 | (defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)) | ||
15 | #error "FIXME: OMAP730 doesn't support multiple-OMAP" | ||
16 | #elif defined(CONFIG_ARCH_OMAP730) | ||
17 | #define INT_IH2_IRQ INT_730_IH2_IRQ | ||
18 | #elif defined(CONFIG_ARCH_OMAP15XX) | ||
19 | #define INT_IH2_IRQ INT_1510_IH2_IRQ | ||
20 | #elif defined(CONFIG_ARCH_OMAP16XX) | ||
21 | #define INT_IH2_IRQ INT_1610_IH2_IRQ | ||
22 | #else | ||
23 | #warning "IH2 IRQ defaulted" | ||
24 | #define INT_IH2_IRQ INT_1510_IH2_IRQ | ||
25 | #endif | ||
26 | |||
13 | .macro disable_fiq | 27 | .macro disable_fiq |
14 | .endm | 28 | .endm |
15 | 29 | ||
diff --git a/include/asm-arm/arch-omap/fpga.h b/include/asm-arm/arch-omap/fpga.h index 676807dc50e1..6a883e0bdbb8 100644 --- a/include/asm-arm/arch-omap/fpga.h +++ b/include/asm-arm/arch-omap/fpga.h | |||
@@ -19,7 +19,7 @@ | |||
19 | #ifndef __ASM_ARCH_OMAP_FPGA_H | 19 | #ifndef __ASM_ARCH_OMAP_FPGA_H |
20 | #define __ASM_ARCH_OMAP_FPGA_H | 20 | #define __ASM_ARCH_OMAP_FPGA_H |
21 | 21 | ||
22 | #if defined(CONFIG_MACH_OMAP_INNOVATOR) && defined(CONFIG_ARCH_OMAP1510) | 22 | #if defined(CONFIG_MACH_OMAP_INNOVATOR) && defined(CONFIG_ARCH_OMAP15XX) |
23 | extern void omap1510_fpga_init_irq(void); | 23 | extern void omap1510_fpga_init_irq(void); |
24 | #else | 24 | #else |
25 | #define omap1510_fpga_init_irq() (0) | 25 | #define omap1510_fpga_init_irq() (0) |
@@ -77,6 +77,8 @@ struct h2p2_dbg_fpga { | |||
77 | #define H2P2_DBG_FPGA_LOAD_METER_SIZE 11 | 77 | #define H2P2_DBG_FPGA_LOAD_METER_SIZE 11 |
78 | #define H2P2_DBG_FPGA_LOAD_METER_MASK ((1 << H2P2_DBG_FPGA_LOAD_METER_SIZE) - 1) | 78 | #define H2P2_DBG_FPGA_LOAD_METER_MASK ((1 << H2P2_DBG_FPGA_LOAD_METER_SIZE) - 1) |
79 | 79 | ||
80 | #define H2P2_DBG_FPGA_P2_LED_TIMER (1 << 0) | ||
81 | #define H2P2_DBG_FPGA_P2_LED_IDLE (1 << 1) | ||
80 | 82 | ||
81 | /* | 83 | /* |
82 | * --------------------------------------------------------------------------- | 84 | * --------------------------------------------------------------------------- |
diff --git a/include/asm-arm/arch-omap/gpio.h b/include/asm-arm/arch-omap/gpio.h index 74cb2b93b700..1b3885741ac1 100644 --- a/include/asm-arm/arch-omap/gpio.h +++ b/include/asm-arm/arch-omap/gpio.h | |||
@@ -67,7 +67,7 @@ | |||
67 | 67 | ||
68 | #define OMAP_GPIO_IRQ(nr) (OMAP_GPIO_IS_MPUIO(nr) ? \ | 68 | #define OMAP_GPIO_IRQ(nr) (OMAP_GPIO_IS_MPUIO(nr) ? \ |
69 | IH_MPUIO_BASE + ((nr) & 0x0f) : \ | 69 | IH_MPUIO_BASE + ((nr) & 0x0f) : \ |
70 | IH_GPIO_BASE + ((nr) & 0x3f)) | 70 | IH_GPIO_BASE + (nr)) |
71 | 71 | ||
72 | extern int omap_gpio_init(void); /* Call from board init only */ | 72 | extern int omap_gpio_init(void); /* Call from board init only */ |
73 | extern int omap_request_gpio(int gpio); | 73 | extern int omap_request_gpio(int gpio); |
diff --git a/include/asm-arm/arch-omap/hardware.h b/include/asm-arm/arch-omap/hardware.h index 60201e1dd6ad..5406b875c422 100644 --- a/include/asm-arm/arch-omap/hardware.h +++ b/include/asm-arm/arch-omap/hardware.h | |||
@@ -267,8 +267,6 @@ | |||
267 | #define OMAP_LPG2_LCR (OMAP_LPG2_BASE + 0x00) | 267 | #define OMAP_LPG2_LCR (OMAP_LPG2_BASE + 0x00) |
268 | #define OMAP_LPG2_PMR (OMAP_LPG2_BASE + 0x04) | 268 | #define OMAP_LPG2_PMR (OMAP_LPG2_BASE + 0x04) |
269 | 269 | ||
270 | #ifndef __ASSEMBLER__ | ||
271 | |||
272 | /* | 270 | /* |
273 | * --------------------------------------------------------------------------- | 271 | * --------------------------------------------------------------------------- |
274 | * Processor specific defines | 272 | * Processor specific defines |
@@ -277,13 +275,11 @@ | |||
277 | 275 | ||
278 | #include "omap730.h" | 276 | #include "omap730.h" |
279 | #include "omap1510.h" | 277 | #include "omap1510.h" |
280 | |||
281 | #ifdef CONFIG_ARCH_OMAP24XX | ||
282 | #include "omap24xx.h" | 278 | #include "omap24xx.h" |
283 | #endif | ||
284 | |||
285 | #include "omap16xx.h" | 279 | #include "omap16xx.h" |
286 | 280 | ||
281 | #ifndef __ASSEMBLER__ | ||
282 | |||
287 | /* | 283 | /* |
288 | * --------------------------------------------------------------------------- | 284 | * --------------------------------------------------------------------------- |
289 | * Board specific defines | 285 | * Board specific defines |
diff --git a/include/asm-arm/arch-omap/io.h b/include/asm-arm/arch-omap/io.h index 3d5bcd545082..f5bcc9a1aed6 100644 --- a/include/asm-arm/arch-omap/io.h +++ b/include/asm-arm/arch-omap/io.h | |||
@@ -52,23 +52,33 @@ | |||
52 | * ---------------------------------------------------------------------------- | 52 | * ---------------------------------------------------------------------------- |
53 | */ | 53 | */ |
54 | 54 | ||
55 | #define PCIO_BASE 0 | ||
56 | |||
55 | #if defined(CONFIG_ARCH_OMAP1) | 57 | #if defined(CONFIG_ARCH_OMAP1) |
58 | |||
56 | #define IO_PHYS 0xFFFB0000 | 59 | #define IO_PHYS 0xFFFB0000 |
57 | #define IO_OFFSET -0x01000000 /* Virtual IO = 0xfefb0000 */ | 60 | #define IO_OFFSET 0x01000000 /* Virtual IO = 0xfefb0000 */ |
58 | #define IO_SIZE 0x40000 | 61 | #define IO_SIZE 0x40000 |
62 | #define IO_VIRT (IO_PHYS - IO_OFFSET) | ||
63 | #define IO_ADDRESS(pa) ((pa) - IO_OFFSET) | ||
64 | #define io_p2v(pa) ((pa) - IO_OFFSET) | ||
65 | #define io_v2p(va) ((va) + IO_OFFSET) | ||
59 | 66 | ||
60 | #elif defined(CONFIG_ARCH_OMAP2) | 67 | #elif defined(CONFIG_ARCH_OMAP2) |
61 | #define IO_PHYS 0x48000000 /* L4 peripherals; other stuff has to be mapped * | ||
62 | * manually. */ | ||
63 | #define IO_OFFSET 0x90000000 /* Virtual IO = 0xd8000000 */ | ||
64 | #define IO_SIZE 0x08000000 | ||
65 | #endif | ||
66 | 68 | ||
67 | #define IO_VIRT (IO_PHYS + IO_OFFSET) | 69 | /* We map both L3 and L4 on OMAP2 */ |
68 | #define IO_ADDRESS(x) ((x) + IO_OFFSET) | 70 | #define L3_24XX_PHYS L3_24XX_BASE /* 0x68000000 */ |
69 | #define PCIO_BASE 0 | 71 | #define L3_24XX_VIRT 0xf8000000 |
70 | #define io_p2v(x) ((x) + IO_OFFSET) | 72 | #define L3_24XX_SIZE SZ_1M /* 44kB of 128MB used, want 1MB sect */ |
71 | #define io_v2p(x) ((x) - IO_OFFSET) | 73 | #define L4_24XX_PHYS L4_24XX_BASE /* 0x48000000 */ |
74 | #define L4_24XX_VIRT 0xd8000000 | ||
75 | #define L4_24XX_SIZE SZ_1M /* 1MB of 128MB used, want 1MB sect */ | ||
76 | #define IO_OFFSET 0x90000000 | ||
77 | #define IO_ADDRESS(pa) ((pa) + IO_OFFSET) /* Works for L3 and L4 */ | ||
78 | #define io_p2v(pa) ((pa) + IO_OFFSET) /* Works for L3 and L4 */ | ||
79 | #define io_v2p(va) ((va) - IO_OFFSET) /* Works for L3 and L4 */ | ||
80 | |||
81 | #endif | ||
72 | 82 | ||
73 | #ifndef __ASSEMBLER__ | 83 | #ifndef __ASSEMBLER__ |
74 | 84 | ||
diff --git a/include/asm-arm/arch-omap/irqs.h b/include/asm-arm/arch-omap/irqs.h index 74e108ccac16..9779686bdceb 100644 --- a/include/asm-arm/arch-omap/irqs.h +++ b/include/asm-arm/arch-omap/irqs.h | |||
@@ -22,8 +22,8 @@ | |||
22 | * are different. | 22 | * are different. |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #ifndef __ASM_ARCH_OMAP1510_IRQS_H | 25 | #ifndef __ASM_ARCH_OMAP15XX_IRQS_H |
26 | #define __ASM_ARCH_OMAP1510_IRQS_H | 26 | #define __ASM_ARCH_OMAP15XX_IRQS_H |
27 | 27 | ||
28 | /* | 28 | /* |
29 | * IRQ numbers for interrupt handler 1 | 29 | * IRQ numbers for interrupt handler 1 |
@@ -31,7 +31,6 @@ | |||
31 | * NOTE: See also the OMAP-1510 and 1610 specific IRQ numbers below | 31 | * NOTE: See also the OMAP-1510 and 1610 specific IRQ numbers below |
32 | * | 32 | * |
33 | */ | 33 | */ |
34 | #define INT_IH2_IRQ 0 | ||
35 | #define INT_CAMERA 1 | 34 | #define INT_CAMERA 1 |
36 | #define INT_FIQ 3 | 35 | #define INT_FIQ 3 |
37 | #define INT_RTDX 6 | 36 | #define INT_RTDX 6 |
@@ -60,6 +59,7 @@ | |||
60 | /* | 59 | /* |
61 | * OMAP-1510 specific IRQ numbers for interrupt handler 1 | 60 | * OMAP-1510 specific IRQ numbers for interrupt handler 1 |
62 | */ | 61 | */ |
62 | #define INT_1510_IH2_IRQ 0 | ||
63 | #define INT_1510_RES2 2 | 63 | #define INT_1510_RES2 2 |
64 | #define INT_1510_SPI_TX 4 | 64 | #define INT_1510_SPI_TX 4 |
65 | #define INT_1510_SPI_RX 5 | 65 | #define INT_1510_SPI_RX 5 |
@@ -71,6 +71,7 @@ | |||
71 | /* | 71 | /* |
72 | * OMAP-1610 specific IRQ numbers for interrupt handler 1 | 72 | * OMAP-1610 specific IRQ numbers for interrupt handler 1 |
73 | */ | 73 | */ |
74 | #define INT_1610_IH2_IRQ 0 | ||
74 | #define INT_1610_IH2_FIQ 2 | 75 | #define INT_1610_IH2_FIQ 2 |
75 | #define INT_1610_McBSP2_TX 4 | 76 | #define INT_1610_McBSP2_TX 4 |
76 | #define INT_1610_McBSP2_RX 5 | 77 | #define INT_1610_McBSP2_RX 5 |
@@ -231,6 +232,12 @@ | |||
231 | #define INT_730_DMA_CH15 (62 + IH2_BASE) | 232 | #define INT_730_DMA_CH15 (62 + IH2_BASE) |
232 | #define INT_730_NAND (63 + IH2_BASE) | 233 | #define INT_730_NAND (63 + IH2_BASE) |
233 | 234 | ||
235 | #define INT_24XX_SYS_NIRQ 7 | ||
236 | #define INT_24XX_SDMA_IRQ0 12 | ||
237 | #define INT_24XX_SDMA_IRQ1 13 | ||
238 | #define INT_24XX_SDMA_IRQ2 14 | ||
239 | #define INT_24XX_SDMA_IRQ3 15 | ||
240 | #define INT_24XX_DSS_IRQ 25 | ||
234 | #define INT_24XX_GPIO_BANK1 29 | 241 | #define INT_24XX_GPIO_BANK1 29 |
235 | #define INT_24XX_GPIO_BANK2 30 | 242 | #define INT_24XX_GPIO_BANK2 30 |
236 | #define INT_24XX_GPIO_BANK3 31 | 243 | #define INT_24XX_GPIO_BANK3 31 |
diff --git a/include/asm-arm/arch-omap/memory.h b/include/asm-arm/arch-omap/memory.h index bf545b6e0a26..df50dd53e1dd 100644 --- a/include/asm-arm/arch-omap/memory.h +++ b/include/asm-arm/arch-omap/memory.h | |||
@@ -61,7 +61,7 @@ | |||
61 | * Note that the is_lbus_device() test is not very efficient on 1510 | 61 | * Note that the is_lbus_device() test is not very efficient on 1510 |
62 | * because of the strncmp(). | 62 | * because of the strncmp(). |
63 | */ | 63 | */ |
64 | #ifdef CONFIG_ARCH_OMAP1510 | 64 | #ifdef CONFIG_ARCH_OMAP15XX |
65 | 65 | ||
66 | /* | 66 | /* |
67 | * OMAP-1510 Local Bus address offset | 67 | * OMAP-1510 Local Bus address offset |
@@ -84,7 +84,7 @@ | |||
84 | virt_to_lbus(addr) : \ | 84 | virt_to_lbus(addr) : \ |
85 | __virt_to_bus(addr);}) | 85 | __virt_to_bus(addr);}) |
86 | 86 | ||
87 | #endif /* CONFIG_ARCH_OMAP1510 */ | 87 | #endif /* CONFIG_ARCH_OMAP15XX */ |
88 | 88 | ||
89 | #endif | 89 | #endif |
90 | 90 | ||
diff --git a/include/asm-arm/arch-omap/menelaus.h b/include/asm-arm/arch-omap/menelaus.h new file mode 100644 index 000000000000..46be8b8d6346 --- /dev/null +++ b/include/asm-arm/arch-omap/menelaus.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * linux/include/asm-arm/arch-omap/menelaus.h | ||
3 | * | ||
4 | * Functions to access Menelaus power management chip | ||
5 | */ | ||
6 | |||
7 | #ifndef __ASM_ARCH_MENELAUS_H | ||
8 | #define __ASM_ARCH_MENELAUS_H | ||
9 | |||
10 | extern void menelaus_mmc_register(void (*callback)(u8 card_mask), | ||
11 | unsigned long data); | ||
12 | extern void menelaus_mmc_remove(void); | ||
13 | extern void menelaus_mmc_opendrain(int enable); | ||
14 | |||
15 | #if defined(CONFIG_ARCH_OMAP24XX) && defined(CONFIG_MENELAUS) | ||
16 | #define omap_has_menelaus() 1 | ||
17 | #else | ||
18 | #define omap_has_menelaus() 0 | ||
19 | #endif | ||
20 | |||
21 | #endif | ||
22 | |||
diff --git a/include/asm-arm/arch-omap/mux.h b/include/asm-arm/arch-omap/mux.h index 1b1ad4105349..13415a9aab06 100644 --- a/include/asm-arm/arch-omap/mux.h +++ b/include/asm-arm/arch-omap/mux.h | |||
@@ -4,7 +4,7 @@ | |||
4 | * Table of the Omap register configurations for the FUNC_MUX and | 4 | * Table of the Omap register configurations for the FUNC_MUX and |
5 | * PULL_DWN combinations. | 5 | * PULL_DWN combinations. |
6 | * | 6 | * |
7 | * Copyright (C) 2003 Nokia Corporation | 7 | * Copyright (C) 2003 - 2005 Nokia Corporation |
8 | * | 8 | * |
9 | * Written by Tony Lindgren <tony.lindgren@nokia.com> | 9 | * Written by Tony Lindgren <tony.lindgren@nokia.com> |
10 | * | 10 | * |
@@ -58,6 +58,16 @@ | |||
58 | .pu_pd_reg = PU_PD_SEL_##reg, \ | 58 | .pu_pd_reg = PU_PD_SEL_##reg, \ |
59 | .pu_pd_val = status, | 59 | .pu_pd_val = status, |
60 | 60 | ||
61 | #define MUX_REG_730(reg, mode_offset, mode) .mux_reg_name = "OMAP730_IO_CONF_"#reg, \ | ||
62 | .mux_reg = OMAP730_IO_CONF_##reg, \ | ||
63 | .mask_offset = mode_offset, \ | ||
64 | .mask = mode, | ||
65 | |||
66 | #define PULL_REG_730(reg, bit, status) .pull_name = "OMAP730_IO_CONF_"#reg, \ | ||
67 | .pull_reg = OMAP730_IO_CONF_##reg, \ | ||
68 | .pull_bit = bit, \ | ||
69 | .pull_val = status, | ||
70 | |||
61 | #else | 71 | #else |
62 | 72 | ||
63 | #define MUX_REG(reg, mode_offset, mode) .mux_reg = FUNC_MUX_CTRL_##reg, \ | 73 | #define MUX_REG(reg, mode_offset, mode) .mux_reg = FUNC_MUX_CTRL_##reg, \ |
@@ -71,6 +81,15 @@ | |||
71 | #define PU_PD_REG(reg, status) .pu_pd_reg = PU_PD_SEL_##reg, \ | 81 | #define PU_PD_REG(reg, status) .pu_pd_reg = PU_PD_SEL_##reg, \ |
72 | .pu_pd_val = status, | 82 | .pu_pd_val = status, |
73 | 83 | ||
84 | #define MUX_REG_730(reg, mode_offset, mode) \ | ||
85 | .mux_reg = OMAP730_IO_CONF_##reg, \ | ||
86 | .mask_offset = mode_offset, \ | ||
87 | .mask = mode, | ||
88 | |||
89 | #define PULL_REG_730(reg, bit, status) .pull_reg = OMAP730_IO_CONF_##reg, \ | ||
90 | .pull_bit = bit, \ | ||
91 | .pull_val = status, | ||
92 | |||
74 | #endif /* CONFIG_OMAP_MUX_DEBUG */ | 93 | #endif /* CONFIG_OMAP_MUX_DEBUG */ |
75 | 94 | ||
76 | #define MUX_CFG(desc, mux_reg, mode_offset, mode, \ | 95 | #define MUX_CFG(desc, mux_reg, mode_offset, mode, \ |
@@ -84,13 +103,44 @@ | |||
84 | PU_PD_REG(pu_pd_reg, pu_pd_status) \ | 103 | PU_PD_REG(pu_pd_reg, pu_pd_status) \ |
85 | }, | 104 | }, |
86 | 105 | ||
106 | |||
107 | /* | ||
108 | * OMAP730 has a slightly different config for the pin mux. | ||
109 | * - config regs are the OMAP730_IO_CONF_x regs (see omap730.h) regs and | ||
110 | * not the FUNC_MUX_CTRL_x regs from hardware.h | ||
111 | * - for pull-up/down, only has one enable bit which is is in the same register | ||
112 | * as mux config | ||
113 | */ | ||
114 | #define MUX_CFG_730(desc, mux_reg, mode_offset, mode, \ | ||
115 | pull_reg, pull_bit, pull_status, \ | ||
116 | pu_pd_reg, pu_pd_status, debug_status)\ | ||
117 | { \ | ||
118 | .name = desc, \ | ||
119 | .debug = debug_status, \ | ||
120 | MUX_REG_730(mux_reg, mode_offset, mode) \ | ||
121 | PULL_REG_730(mux_reg, pull_bit, pull_status) \ | ||
122 | PU_PD_REG(pu_pd_reg, pu_pd_status) \ | ||
123 | }, | ||
124 | |||
125 | #define MUX_CFG_24XX(desc, reg_offset, mode, \ | ||
126 | pull_en, pull_mode, dbg) \ | ||
127 | { \ | ||
128 | .name = desc, \ | ||
129 | .debug = dbg, \ | ||
130 | .mux_reg = reg_offset, \ | ||
131 | .mask = mode, \ | ||
132 | .pull_val = pull_en, \ | ||
133 | .pu_pd_val = pull_mode, \ | ||
134 | }, | ||
135 | |||
136 | |||
87 | #define PULL_DISABLED 0 | 137 | #define PULL_DISABLED 0 |
88 | #define PULL_ENABLED 1 | 138 | #define PULL_ENABLED 1 |
89 | 139 | ||
90 | #define PULL_DOWN 0 | 140 | #define PULL_DOWN 0 |
91 | #define PULL_UP 1 | 141 | #define PULL_UP 1 |
92 | 142 | ||
93 | typedef struct { | 143 | struct pin_config { |
94 | char *name; | 144 | char *name; |
95 | unsigned char busy; | 145 | unsigned char busy; |
96 | unsigned char debug; | 146 | unsigned char debug; |
@@ -108,13 +158,23 @@ typedef struct { | |||
108 | const char *pu_pd_name; | 158 | const char *pu_pd_name; |
109 | const unsigned int pu_pd_reg; | 159 | const unsigned int pu_pd_reg; |
110 | const unsigned char pu_pd_val; | 160 | const unsigned char pu_pd_val; |
111 | } reg_cfg_set; | 161 | }; |
112 | 162 | ||
113 | /* | 163 | enum omap730_index { |
114 | * Lookup table for FUNC_MUX and PULL_DWN register combinations for each | 164 | /* OMAP 730 keyboard */ |
115 | * device. See also reg_cfg_table below for the register values. | 165 | E2_730_KBR0, |
116 | */ | 166 | J7_730_KBR1, |
117 | typedef enum { | 167 | E1_730_KBR2, |
168 | F3_730_KBR3, | ||
169 | D2_730_KBR4, | ||
170 | C2_730_KBC0, | ||
171 | D3_730_KBC1, | ||
172 | E4_730_KBC2, | ||
173 | F4_730_KBC3, | ||
174 | E3_730_KBC4, | ||
175 | }; | ||
176 | |||
177 | enum omap1xxx_index { | ||
118 | /* UART1 (BT_UART_GATING)*/ | 178 | /* UART1 (BT_UART_GATING)*/ |
119 | UART1_TX = 0, | 179 | UART1_TX = 0, |
120 | UART1_RTS, | 180 | UART1_RTS, |
@@ -331,245 +391,34 @@ typedef enum { | |||
331 | V10_1610_CF_IREQ, | 391 | V10_1610_CF_IREQ, |
332 | W10_1610_CF_RESET, | 392 | W10_1610_CF_RESET, |
333 | W11_1610_CF_CD1, | 393 | W11_1610_CF_CD1, |
334 | } reg_cfg_t; | 394 | }; |
335 | 395 | ||
336 | #if defined(__MUX_C__) && defined(CONFIG_OMAP_MUX) | 396 | enum omap24xx_index { |
397 | /* 24xx I2C */ | ||
398 | M19_24XX_I2C1_SCL, | ||
399 | L15_24XX_I2C1_SDA, | ||
400 | J15_24XX_I2C2_SCL, | ||
401 | H19_24XX_I2C2_SDA, | ||
337 | 402 | ||
338 | /* | 403 | /* 24xx Menelaus interrupt */ |
339 | * Table of various FUNC_MUX and PULL_DWN combinations for each device. | 404 | W19_24XX_SYS_NIRQ, |
340 | * See also reg_cfg_t above for the lookup table. | ||
341 | */ | ||
342 | static const reg_cfg_set __initdata_or_module | ||
343 | reg_cfg_table[] = { | ||
344 | /* | ||
345 | * description mux mode mux pull pull pull pu_pd pu dbg | ||
346 | * reg offset mode reg bit ena reg | ||
347 | */ | ||
348 | MUX_CFG("UART1_TX", 9, 21, 1, 2, 3, 0, NA, 0, 0) | ||
349 | MUX_CFG("UART1_RTS", 9, 12, 1, 2, 0, 0, NA, 0, 0) | ||
350 | |||
351 | /* UART2 (COM_UART_GATING), conflicts with USB2 */ | ||
352 | MUX_CFG("UART2_TX", C, 27, 1, 3, 3, 0, NA, 0, 0) | ||
353 | MUX_CFG("UART2_RX", C, 18, 0, 3, 1, 1, NA, 0, 0) | ||
354 | MUX_CFG("UART2_CTS", C, 21, 0, 3, 1, 1, NA, 0, 0) | ||
355 | MUX_CFG("UART2_RTS", C, 24, 1, 3, 2, 0, NA, 0, 0) | ||
356 | |||
357 | /* UART3 (GIGA_UART_GATING) */ | ||
358 | MUX_CFG("UART3_TX", 6, 0, 1, 0, 30, 0, NA, 0, 0) | ||
359 | MUX_CFG("UART3_RX", 6, 3, 0, 0, 31, 1, NA, 0, 0) | ||
360 | MUX_CFG("UART3_CTS", 5, 12, 2, 0, 24, 0, NA, 0, 0) | ||
361 | MUX_CFG("UART3_RTS", 5, 15, 2, 0, 25, 0, NA, 0, 0) | ||
362 | MUX_CFG("UART3_CLKREQ", 9, 27, 0, 2, 5, 0, NA, 0, 0) | ||
363 | MUX_CFG("UART3_BCLK", A, 0, 0, 2, 6, 0, NA, 0, 0) | ||
364 | MUX_CFG("Y15_1610_UART3_RTS", A, 0, 1, 2, 6, 0, NA, 0, 0) | ||
365 | |||
366 | /* PWT & PWL, conflicts with UART3 */ | ||
367 | MUX_CFG("PWT", 6, 0, 2, 0, 30, 0, NA, 0, 0) | ||
368 | MUX_CFG("PWL", 6, 3, 1, 0, 31, 1, NA, 0, 0) | ||
369 | |||
370 | /* USB internal master generic */ | ||
371 | MUX_CFG("R18_USB_VBUS", 7, 9, 2, 1, 11, 0, NA, 0, 1) | ||
372 | MUX_CFG("R18_1510_USB_GPIO0", 7, 9, 0, 1, 11, 1, NA, 0, 1) | ||
373 | /* works around erratum: W4_USB_PUEN and W4_USB_PUDIS are switched! */ | ||
374 | MUX_CFG("W4_USB_PUEN", D, 3, 3, 3, 5, 1, NA, 0, 1) | ||
375 | MUX_CFG("W4_USB_CLKO", D, 3, 1, 3, 5, 0, NA, 0, 1) | ||
376 | MUX_CFG("W4_USB_HIGHZ", D, 3, 4, 3, 5, 0, 3, 0, 1) | ||
377 | MUX_CFG("W4_GPIO58", D, 3, 7, 3, 5, 0, 3, 0, 1) | ||
378 | |||
379 | /* USB1 master */ | ||
380 | MUX_CFG("USB1_SUSP", 8, 27, 2, 1, 27, 0, NA, 0, 1) | ||
381 | MUX_CFG("USB1_SE0", 9, 0, 2, 1, 28, 0, NA, 0, 1) | ||
382 | MUX_CFG("W13_1610_USB1_SE0", 9, 0, 4, 1, 28, 0, NA, 0, 1) | ||
383 | MUX_CFG("USB1_TXEN", 9, 3, 2, 1, 29, 0, NA, 0, 1) | ||
384 | MUX_CFG("USB1_TXD", 9, 24, 1, 2, 4, 0, NA, 0, 1) | ||
385 | MUX_CFG("USB1_VP", A, 3, 1, 2, 7, 0, NA, 0, 1) | ||
386 | MUX_CFG("USB1_VM", A, 6, 1, 2, 8, 0, NA, 0, 1) | ||
387 | MUX_CFG("USB1_RCV", A, 9, 1, 2, 9, 0, NA, 0, 1) | ||
388 | MUX_CFG("USB1_SPEED", A, 12, 2, 2, 10, 0, NA, 0, 1) | ||
389 | MUX_CFG("R13_1610_USB1_SPEED", A, 12, 5, 2, 10, 0, NA, 0, 1) | ||
390 | MUX_CFG("R13_1710_USB1_SEO", A, 12, 5, 2, 10, 0, NA, 0, 1) | ||
391 | |||
392 | /* USB2 master */ | ||
393 | MUX_CFG("USB2_SUSP", B, 3, 1, 2, 17, 0, NA, 0, 1) | ||
394 | MUX_CFG("USB2_VP", B, 6, 1, 2, 18, 0, NA, 0, 1) | ||
395 | MUX_CFG("USB2_TXEN", B, 9, 1, 2, 19, 0, NA, 0, 1) | ||
396 | MUX_CFG("USB2_VM", C, 18, 1, 3, 0, 0, NA, 0, 1) | ||
397 | MUX_CFG("USB2_RCV", C, 21, 1, 3, 1, 0, NA, 0, 1) | ||
398 | MUX_CFG("USB2_SE0", C, 24, 2, 3, 2, 0, NA, 0, 1) | ||
399 | MUX_CFG("USB2_TXD", C, 27, 2, 3, 3, 0, NA, 0, 1) | ||
400 | |||
401 | /* OMAP-1510 GPIO */ | ||
402 | MUX_CFG("R18_1510_GPIO0", 7, 9, 0, 1, 11, 1, 0, 0, 1) | ||
403 | MUX_CFG("R19_1510_GPIO1", 7, 6, 0, 1, 10, 1, 0, 0, 1) | ||
404 | MUX_CFG("M14_1510_GPIO2", 7, 3, 0, 1, 9, 1, 0, 0, 1) | ||
405 | |||
406 | /* OMAP1610 GPIO */ | ||
407 | MUX_CFG("P18_1610_GPIO3", 7, 0, 0, 1, 8, 0, NA, 0, 1) | ||
408 | MUX_CFG("Y15_1610_GPIO17", A, 0, 7, 2, 6, 0, NA, 0, 1) | ||
409 | |||
410 | /* OMAP-1710 GPIO */ | ||
411 | MUX_CFG("R18_1710_GPIO0", 7, 9, 0, 1, 11, 1, 1, 1, 1) | ||
412 | MUX_CFG("V2_1710_GPIO10", F, 27, 1, 4, 3, 1, 4, 1, 1) | ||
413 | MUX_CFG("N21_1710_GPIO14", 6, 9, 0, 1, 1, 1, 1, 1, 1) | ||
414 | MUX_CFG("W15_1710_GPIO40", 9, 27, 7, 2, 5, 1, 2, 1, 1) | ||
415 | |||
416 | /* MPUIO */ | ||
417 | MUX_CFG("MPUIO2", 7, 18, 0, 1, 14, 1, NA, 0, 1) | ||
418 | MUX_CFG("N15_1610_MPUIO2", 7, 18, 0, 1, 14, 1, 1, 0, 1) | ||
419 | MUX_CFG("MPUIO4", 7, 15, 0, 1, 13, 1, NA, 0, 1) | ||
420 | MUX_CFG("MPUIO5", 7, 12, 0, 1, 12, 1, NA, 0, 1) | ||
421 | |||
422 | MUX_CFG("T20_1610_MPUIO5", 7, 12, 0, 1, 12, 0, 3, 0, 1) | ||
423 | MUX_CFG("W11_1610_MPUIO6", 10, 15, 2, 3, 8, 0, 3, 0, 1) | ||
424 | MUX_CFG("V10_1610_MPUIO7", A, 24, 2, 2, 14, 0, 2, 0, 1) | ||
425 | MUX_CFG("W11_1610_MPUIO9", 10, 15, 1, 3, 8, 0, 3, 0, 1) | ||
426 | MUX_CFG("V10_1610_MPUIO10", A, 24, 1, 2, 14, 0, 2, 0, 1) | ||
427 | MUX_CFG("W10_1610_MPUIO11", A, 18, 2, 2, 11, 0, 2, 0, 1) | ||
428 | MUX_CFG("E20_1610_MPUIO13", 3, 21, 1, 0, 7, 0, 0, 0, 1) | ||
429 | MUX_CFG("U20_1610_MPUIO14", 9, 6, 6, 0, 30, 0, 0, 0, 1) | ||
430 | MUX_CFG("E19_1610_MPUIO15", 3, 18, 1, 0, 6, 0, 0, 0, 1) | ||
431 | |||
432 | /* MCBSP2 */ | ||
433 | MUX_CFG("MCBSP2_CLKR", C, 6, 0, 2, 27, 1, NA, 0, 1) | ||
434 | MUX_CFG("MCBSP2_CLKX", C, 9, 0, 2, 29, 1, NA, 0, 1) | ||
435 | MUX_CFG("MCBSP2_DR", C, 0, 0, 2, 26, 1, NA, 0, 1) | ||
436 | MUX_CFG("MCBSP2_DX", C, 15, 0, 2, 31, 1, NA, 0, 1) | ||
437 | MUX_CFG("MCBSP2_FSR", C, 12, 0, 2, 30, 1, NA, 0, 1) | ||
438 | MUX_CFG("MCBSP2_FSX", C, 3, 0, 2, 27, 1, NA, 0, 1) | ||
439 | |||
440 | /* MCBSP3 NOTE: Mode must 1 for clock */ | ||
441 | MUX_CFG("MCBSP3_CLKX", 9, 3, 1, 1, 29, 0, NA, 0, 1) | ||
442 | |||
443 | /* Misc ballouts */ | ||
444 | MUX_CFG("BALLOUT_V8_ARMIO3", B, 18, 0, 2, 25, 1, NA, 0, 1) | ||
445 | MUX_CFG("N20_HDQ", 6, 18, 1, 1, 4, 0, 1, 4, 0) | ||
446 | |||
447 | /* OMAP-1610 MMC2 */ | ||
448 | MUX_CFG("W8_1610_MMC2_DAT0", B, 21, 6, 2, 23, 1, 2, 1, 1) | ||
449 | MUX_CFG("V8_1610_MMC2_DAT1", B, 27, 6, 2, 25, 1, 2, 1, 1) | ||
450 | MUX_CFG("W15_1610_MMC2_DAT2", 9, 12, 6, 2, 5, 1, 2, 1, 1) | ||
451 | MUX_CFG("R10_1610_MMC2_DAT3", B, 18, 6, 2, 22, 1, 2, 1, 1) | ||
452 | MUX_CFG("Y10_1610_MMC2_CLK", B, 3, 6, 2, 17, 0, 2, 0, 1) | ||
453 | MUX_CFG("Y8_1610_MMC2_CMD", B, 24, 6, 2, 24, 1, 2, 1, 1) | ||
454 | MUX_CFG("V9_1610_MMC2_CMDDIR", B, 12, 6, 2, 20, 0, 2, 1, 1) | ||
455 | MUX_CFG("V5_1610_MMC2_DATDIR0", B, 15, 6, 2, 21, 0, 2, 1, 1) | ||
456 | MUX_CFG("W19_1610_MMC2_DATDIR1", 8, 15, 6, 1, 23, 0, 1, 1, 1) | ||
457 | MUX_CFG("R18_1610_MMC2_CLKIN", 7, 9, 6, 1, 11, 0, 1, 11, 1) | ||
458 | |||
459 | /* OMAP-1610 External Trace Interface */ | ||
460 | MUX_CFG("M19_1610_ETM_PSTAT0", 5, 27, 1, 0, 29, 0, 0, 0, 1) | ||
461 | MUX_CFG("L15_1610_ETM_PSTAT1", 5, 24, 1, 0, 28, 0, 0, 0, 1) | ||
462 | MUX_CFG("L18_1610_ETM_PSTAT2", 5, 21, 1, 0, 27, 0, 0, 0, 1) | ||
463 | MUX_CFG("L19_1610_ETM_D0", 5, 18, 1, 0, 26, 0, 0, 0, 1) | ||
464 | MUX_CFG("J19_1610_ETM_D6", 5, 0, 1, 0, 20, 0, 0, 0, 1) | ||
465 | MUX_CFG("J18_1610_ETM_D7", 5, 27, 1, 0, 19, 0, 0, 0, 1) | ||
466 | |||
467 | /* OMAP16XX GPIO */ | ||
468 | MUX_CFG("P20_1610_GPIO4", 6, 27, 0, 1, 7, 0, 1, 1, 1) | ||
469 | MUX_CFG("V9_1610_GPIO7", B, 12, 1, 2, 20, 0, 2, 1, 1) | ||
470 | MUX_CFG("W8_1610_GPIO9", B, 21, 0, 2, 23, 0, 2, 1, 1) | ||
471 | MUX_CFG("N20_1610_GPIO11", 6, 18, 0, 1, 4, 0, 1, 1, 1) | ||
472 | MUX_CFG("N19_1610_GPIO13", 6, 12, 0, 1, 2, 0, 1, 1, 1) | ||
473 | MUX_CFG("P10_1610_GPIO22", C, 0, 7, 2, 26, 0, 2, 1, 1) | ||
474 | MUX_CFG("V5_1610_GPIO24", B, 15, 7, 2, 21, 0, 2, 1, 1) | ||
475 | MUX_CFG("AA20_1610_GPIO_41", 9, 9, 7, 1, 31, 0, 1, 1, 1) | ||
476 | MUX_CFG("W19_1610_GPIO48", 8, 15, 7, 1, 23, 1, 1, 0, 1) | ||
477 | MUX_CFG("M7_1610_GPIO62", 10, 0, 0, 4, 24, 0, 4, 0, 1) | ||
478 | MUX_CFG("V14_16XX_GPIO37", 9, 18, 7, 2, 2, 0, 2, 2, 0) | ||
479 | MUX_CFG("R9_16XX_GPIO18", C, 18, 7, 3, 0, 0, 3, 0, 0) | ||
480 | MUX_CFG("L14_16XX_GPIO49", 6, 3, 7, 0, 31, 0, 0, 31, 0) | ||
481 | |||
482 | /* OMAP-1610 uWire */ | ||
483 | MUX_CFG("V19_1610_UWIRE_SCLK", 8, 6, 0, 1, 20, 0, 1, 1, 1) | ||
484 | MUX_CFG("U18_1610_UWIRE_SDI", 8, 0, 0, 1, 18, 0, 1, 1, 1) | ||
485 | MUX_CFG("W21_1610_UWIRE_SDO", 8, 3, 0, 1, 19, 0, 1, 1, 1) | ||
486 | MUX_CFG("N14_1610_UWIRE_CS0", 8, 9, 1, 1, 21, 0, 1, 1, 1) | ||
487 | MUX_CFG("P15_1610_UWIRE_CS3", 8, 12, 1, 1, 22, 0, 1, 1, 1) | ||
488 | MUX_CFG("N15_1610_UWIRE_CS1", 7, 18, 2, 1, 14, 0, NA, 0, 1) | ||
489 | |||
490 | /* OMAP-1610 Flash */ | ||
491 | MUX_CFG("L3_1610_FLASH_CS2B_OE",10, 6, 1, NA, 0, 0, NA, 0, 1) | ||
492 | MUX_CFG("M8_1610_FLASH_CS2B_WE",10, 3, 1, NA, 0, 0, NA, 0, 1) | ||
493 | |||
494 | /* First MMC interface, same on 1510, 1610 and 1710 */ | ||
495 | MUX_CFG("MMC_CMD", A, 27, 0, 2, 15, 1, 2, 1, 1) | ||
496 | MUX_CFG("MMC_DAT1", A, 24, 0, 2, 14, 1, 2, 1, 1) | ||
497 | MUX_CFG("MMC_DAT2", A, 18, 0, 2, 12, 1, 2, 1, 1) | ||
498 | MUX_CFG("MMC_DAT0", B, 0, 0, 2, 16, 1, 2, 1, 1) | ||
499 | MUX_CFG("MMC_CLK", A, 21, 0, NA, 0, 0, NA, 0, 1) | ||
500 | MUX_CFG("MMC_DAT3", 10, 15, 0, 3, 8, 1, 3, 1, 1) | ||
501 | MUX_CFG("M15_1710_MMC_CLKI", 6, 21, 2, 0, 0, 0, NA, 0, 1) | ||
502 | MUX_CFG("P19_1710_MMC_CMDDIR", 6, 24, 6, 0, 0, 0, NA, 0, 1) | ||
503 | MUX_CFG("P20_1710_MMC_DATDIR0", 6, 27, 5, 0, 0, 0, NA, 0, 1) | ||
504 | |||
505 | /* OMAP-1610 USB0 alternate configuration */ | ||
506 | MUX_CFG("W9_USB0_TXEN", B, 9, 5, 2, 19, 0, 2, 0, 1) | ||
507 | MUX_CFG("AA9_USB0_VP", B, 6, 5, 2, 18, 0, 2, 0, 1) | ||
508 | MUX_CFG("Y5_USB0_RCV", C, 21, 5, 3, 1, 0, 1, 0, 1) | ||
509 | MUX_CFG("R9_USB0_VM", C, 18, 5, 3, 0, 0, 3, 0, 1) | ||
510 | MUX_CFG("V6_USB0_TXD", C, 27, 5, 3, 3, 0, 3, 0, 1) | ||
511 | MUX_CFG("W5_USB0_SE0", C, 24, 5, 3, 2, 0, 3, 0, 1) | ||
512 | MUX_CFG("V9_USB0_SPEED", B, 12, 5, 2, 20, 0, 2, 0, 1) | ||
513 | MUX_CFG("Y10_USB0_SUSP", B, 3, 5, 2, 17, 0, 2, 0, 1) | ||
514 | |||
515 | /* USB2 interface */ | ||
516 | MUX_CFG("W9_USB2_TXEN", B, 9, 1, NA, 0, 0, NA, 0, 1) | ||
517 | MUX_CFG("AA9_USB2_VP", B, 6, 1, NA, 0, 0, NA, 0, 1) | ||
518 | MUX_CFG("Y5_USB2_RCV", C, 21, 1, NA, 0, 0, NA, 0, 1) | ||
519 | MUX_CFG("R9_USB2_VM", C, 18, 1, NA, 0, 0, NA, 0, 1) | ||
520 | MUX_CFG("V6_USB2_TXD", C, 27, 2, NA, 0, 0, NA, 0, 1) | ||
521 | MUX_CFG("W5_USB2_SE0", C, 24, 2, NA, 0, 0, NA, 0, 1) | ||
522 | |||
523 | /* 16XX UART */ | ||
524 | MUX_CFG("R13_1610_UART1_TX", A, 12, 6, 2, 10, 0, 2, 10, 1) | ||
525 | MUX_CFG("V14_16XX_UART1_RX", 9, 18, 0, 2, 2, 0, 2, 2, 1) | ||
526 | MUX_CFG("R14_1610_UART1_CTS", 9, 15, 0, 2, 1, 0, 2, 1, 1) | ||
527 | MUX_CFG("AA15_1610_UART1_RTS", 9, 12, 1, 2, 0, 0, 2, 0, 1) | ||
528 | MUX_CFG("R9_16XX_UART2_RX", C, 18, 0, 3, 0, 0, 3, 0, 1) | ||
529 | MUX_CFG("L14_16XX_UART3_RX", 6, 3, 0, 0, 31, 0, 0, 31, 1) | ||
530 | |||
531 | /* I2C interface */ | ||
532 | MUX_CFG("I2C_SCL", 7, 24, 0, NA, 0, 0, NA, 0, 0) | ||
533 | MUX_CFG("I2C_SDA", 7, 27, 0, NA, 0, 0, NA, 0, 0) | ||
534 | |||
535 | /* Keypad */ | ||
536 | MUX_CFG("F18_1610_KBC0", 3, 15, 0, 0, 5, 1, 0, 0, 0) | ||
537 | MUX_CFG("D20_1610_KBC1", 3, 12, 0, 0, 4, 1, 0, 0, 0) | ||
538 | MUX_CFG("D19_1610_KBC2", 3, 9, 0, 0, 3, 1, 0, 0, 0) | ||
539 | MUX_CFG("E18_1610_KBC3", 3, 6, 0, 0, 2, 1, 0, 0, 0) | ||
540 | MUX_CFG("C21_1610_KBC4", 3, 3, 0, 0, 1, 1, 0, 0, 0) | ||
541 | MUX_CFG("G18_1610_KBR0", 4, 0, 0, 0, 10, 1, 0, 1, 0) | ||
542 | MUX_CFG("F19_1610_KBR1", 3, 27, 0, 0, 9, 1, 0, 1, 0) | ||
543 | MUX_CFG("H14_1610_KBR2", 3, 24, 0, 0, 8, 1, 0, 1, 0) | ||
544 | MUX_CFG("E20_1610_KBR3", 3, 21, 0, 0, 7, 1, 0, 1, 0) | ||
545 | MUX_CFG("E19_1610_KBR4", 3, 18, 0, 0, 6, 1, 0, 1, 0) | ||
546 | MUX_CFG("N19_1610_KBR5", 6, 12, 1, 1, 2, 1, 1, 1, 0) | ||
547 | |||
548 | /* Power management */ | ||
549 | MUX_CFG("T20_1610_LOW_PWR", 7, 12, 1, NA, 0, 0, NA, 0, 0) | ||
550 | |||
551 | /* MCLK Settings */ | ||
552 | MUX_CFG("V5_1710_MCLK_ON", B, 15, 0, NA, 0, 0, NA, 0, 0) | ||
553 | MUX_CFG("V5_1710_MCLK_OFF", B, 15, 6, NA, 0, 0, NA, 0, 0) | ||
554 | MUX_CFG("R10_1610_MCLK_ON", B, 18, 0, NA, 22, 0, NA, 1, 0) | ||
555 | MUX_CFG("R10_1610_MCLK_OFF", B, 18, 6, 2, 22, 1, 2, 1, 1) | ||
556 | |||
557 | /* CompactFlash controller, conflicts with MMC1 */ | ||
558 | MUX_CFG("P11_1610_CF_CD2", A, 27, 3, 2, 15, 1, 2, 1, 1) | ||
559 | MUX_CFG("R11_1610_CF_IOIS16", B, 0, 3, 2, 16, 1, 2, 1, 1) | ||
560 | MUX_CFG("V10_1610_CF_IREQ", A, 24, 3, 2, 14, 0, 2, 0, 1) | ||
561 | MUX_CFG("W10_1610_CF_RESET", A, 18, 3, 2, 12, 1, 2, 1, 1) | ||
562 | MUX_CFG("W11_1610_CF_CD1", 10, 15, 3, 3, 8, 1, 3, 1, 1) | ||
563 | }; | ||
564 | 405 | ||
565 | #endif /* __MUX_C__ */ | 406 | /* 24xx GPIO */ |
407 | Y20_24XX_GPIO60, | ||
408 | M15_24XX_GPIO92, | ||
409 | }; | ||
566 | 410 | ||
567 | #ifdef CONFIG_OMAP_MUX | 411 | #ifdef CONFIG_OMAP_MUX |
568 | /* setup pin muxing in Linux */ | 412 | /* setup pin muxing in Linux */ |
569 | extern int omap_cfg_reg(reg_cfg_t reg_cfg); | 413 | extern int omap1_mux_init(void); |
414 | extern int omap2_mux_init(void); | ||
415 | extern int omap_mux_register(struct pin_config * pins, unsigned long size); | ||
416 | extern int omap_cfg_reg(unsigned long reg_cfg); | ||
570 | #else | 417 | #else |
571 | /* boot loader does it all (no warnings from CONFIG_OMAP_MUX_WARNINGS) */ | 418 | /* boot loader does it all (no warnings from CONFIG_OMAP_MUX_WARNINGS) */ |
572 | static inline int omap_cfg_reg(reg_cfg_t reg_cfg) { return 0; } | 419 | static inline int omap1_mux_init(void) { return 0; } |
420 | static inline int omap2_mux_init(void) { return 0; } | ||
421 | static inline int omap_cfg_reg(unsigned long reg_cfg) { return 0; } | ||
573 | #endif | 422 | #endif |
574 | 423 | ||
575 | #endif | 424 | #endif |
diff --git a/include/asm-arm/arch-omap/omap1510.h b/include/asm-arm/arch-omap/omap1510.h index f086a3933906..c575d354850f 100644 --- a/include/asm-arm/arch-omap/omap1510.h +++ b/include/asm-arm/arch-omap/omap1510.h | |||
@@ -25,8 +25,8 @@ | |||
25 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 25 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #ifndef __ASM_ARCH_OMAP1510_H | 28 | #ifndef __ASM_ARCH_OMAP15XX_H |
29 | #define __ASM_ARCH_OMAP1510_H | 29 | #define __ASM_ARCH_OMAP15XX_H |
30 | 30 | ||
31 | /* | 31 | /* |
32 | * ---------------------------------------------------------------------------- | 32 | * ---------------------------------------------------------------------------- |
@@ -44,5 +44,5 @@ | |||
44 | #define OMAP1510_DSPREG_SIZE SZ_128K | 44 | #define OMAP1510_DSPREG_SIZE SZ_128K |
45 | #define OMAP1510_DSPREG_START 0xE1000000 | 45 | #define OMAP1510_DSPREG_START 0xE1000000 |
46 | 46 | ||
47 | #endif /* __ASM_ARCH_OMAP1510_H */ | 47 | #endif /* __ASM_ARCH_OMAP15XX_H */ |
48 | 48 | ||
diff --git a/include/asm-arm/arch-omap/omap24xx.h b/include/asm-arm/arch-omap/omap24xx.h index a9105466a417..6e59805fa654 100644 --- a/include/asm-arm/arch-omap/omap24xx.h +++ b/include/asm-arm/arch-omap/omap24xx.h | |||
@@ -1,15 +1,24 @@ | |||
1 | #ifndef __ASM_ARCH_OMAP24XX_H | 1 | #ifndef __ASM_ARCH_OMAP24XX_H |
2 | #define __ASM_ARCH_OMAP24XX_H | 2 | #define __ASM_ARCH_OMAP24XX_H |
3 | 3 | ||
4 | #define OMAP24XX_L4_IO_BASE 0x48000000 | 4 | /* |
5 | * Please place only base defines here and put the rest in device | ||
6 | * specific headers. Note also that some of these defines are needed | ||
7 | * for omap1 to compile without adding ifdefs. | ||
8 | */ | ||
9 | |||
10 | #define L4_24XX_BASE 0x48000000 | ||
11 | #define L3_24XX_BASE 0x68000000 | ||
5 | 12 | ||
6 | /* interrupt controller */ | 13 | /* interrupt controller */ |
7 | #define OMAP24XX_IC_BASE (OMAP24XX_L4_IO_BASE + 0xfe000) | 14 | #define OMAP24XX_IC_BASE (L4_24XX_BASE + 0xfe000) |
8 | #define VA_IC_BASE IO_ADDRESS(OMAP24XX_IC_BASE) | 15 | #define VA_IC_BASE IO_ADDRESS(OMAP24XX_IC_BASE) |
9 | |||
10 | #define OMAP24XX_IVA_INTC_BASE 0x40000000 | 16 | #define OMAP24XX_IVA_INTC_BASE 0x40000000 |
11 | |||
12 | #define IRQ_SIR_IRQ 0x0040 | 17 | #define IRQ_SIR_IRQ 0x0040 |
13 | 18 | ||
19 | #define OMAP24XX_32KSYNCT_BASE (L4_24XX_BASE + 0x4000) | ||
20 | #define OMAP24XX_PRCM_BASE (L4_24XX_BASE + 0x8000) | ||
21 | #define OMAP24XX_SDRC_BASE (L3_24XX_BASE + 0x9000) | ||
22 | |||
14 | #endif /* __ASM_ARCH_OMAP24XX_H */ | 23 | #endif /* __ASM_ARCH_OMAP24XX_H */ |
15 | 24 | ||
diff --git a/include/asm-arm/arch-omap/omapfb.h b/include/asm-arm/arch-omap/omapfb.h new file mode 100644 index 000000000000..4ba2622cc142 --- /dev/null +++ b/include/asm-arm/arch-omap/omapfb.h | |||
@@ -0,0 +1,281 @@ | |||
1 | /* | ||
2 | * File: include/asm-arm/arch-omap/omapfb.h | ||
3 | * | ||
4 | * Framebuffer driver for TI OMAP boards | ||
5 | * | ||
6 | * Copyright (C) 2004 Nokia Corporation | ||
7 | * Author: Imre Deak <imre.deak@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along | ||
20 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
22 | */ | ||
23 | |||
24 | #ifndef __OMAPFB_H | ||
25 | #define __OMAPFB_H | ||
26 | |||
27 | /* IOCTL commands. */ | ||
28 | |||
29 | #define OMAP_IOW(num, dtype) _IOW('O', num, dtype) | ||
30 | #define OMAP_IOR(num, dtype) _IOR('O', num, dtype) | ||
31 | #define OMAP_IOWR(num, dtype) _IOWR('O', num, dtype) | ||
32 | #define OMAP_IO(num) _IO('O', num) | ||
33 | |||
34 | #define OMAPFB_MIRROR OMAP_IOW(31, int) | ||
35 | #define OMAPFB_SYNC_GFX OMAP_IO(37) | ||
36 | #define OMAPFB_VSYNC OMAP_IO(38) | ||
37 | #define OMAPFB_SET_UPDATE_MODE OMAP_IOW(40, enum omapfb_update_mode) | ||
38 | #define OMAPFB_GET_CAPS OMAP_IOR(42, unsigned long) | ||
39 | #define OMAPFB_GET_UPDATE_MODE OMAP_IOW(43, enum omapfb_update_mode) | ||
40 | #define OMAPFB_LCD_TEST OMAP_IOW(45, int) | ||
41 | #define OMAPFB_CTRL_TEST OMAP_IOW(46, int) | ||
42 | #define OMAPFB_UPDATE_WINDOW OMAP_IOW(47, struct omapfb_update_window) | ||
43 | #define OMAPFB_SETUP_PLANE OMAP_IOW(48, struct omapfb_setup_plane) | ||
44 | #define OMAPFB_ENABLE_PLANE OMAP_IOW(49, struct omapfb_enable_plane) | ||
45 | #define OMAPFB_SET_COLOR_KEY OMAP_IOW(50, struct omapfb_color_key) | ||
46 | |||
47 | #define OMAPFB_CAPS_GENERIC_MASK 0x00000fff | ||
48 | #define OMAPFB_CAPS_LCDC_MASK 0x00fff000 | ||
49 | #define OMAPFB_CAPS_PANEL_MASK 0xff000000 | ||
50 | |||
51 | #define OMAPFB_CAPS_MANUAL_UPDATE 0x00001000 | ||
52 | #define OMAPFB_CAPS_SET_BACKLIGHT 0x01000000 | ||
53 | |||
54 | /* Values from DSP must map to lower 16-bits */ | ||
55 | #define OMAPFB_FORMAT_MASK 0x00ff | ||
56 | #define OMAPFB_FORMAT_FLAG_DOUBLE 0x0100 | ||
57 | |||
58 | enum omapfb_color_format { | ||
59 | OMAPFB_COLOR_RGB565 = 0, | ||
60 | OMAPFB_COLOR_YUV422, | ||
61 | OMAPFB_COLOR_YUV420, | ||
62 | OMAPFB_COLOR_CLUT_8BPP, | ||
63 | OMAPFB_COLOR_CLUT_4BPP, | ||
64 | OMAPFB_COLOR_CLUT_2BPP, | ||
65 | OMAPFB_COLOR_CLUT_1BPP, | ||
66 | }; | ||
67 | |||
68 | struct omapfb_update_window { | ||
69 | u32 x, y; | ||
70 | u32 width, height; | ||
71 | u32 format; | ||
72 | }; | ||
73 | |||
74 | enum omapfb_plane { | ||
75 | OMAPFB_PLANE_GFX = 0, | ||
76 | OMAPFB_PLANE_VID1, | ||
77 | OMAPFB_PLANE_VID2, | ||
78 | }; | ||
79 | |||
80 | enum omapfb_channel_out { | ||
81 | OMAPFB_CHANNEL_OUT_LCD = 0, | ||
82 | OMAPFB_CHANNEL_OUT_DIGIT, | ||
83 | }; | ||
84 | |||
85 | struct omapfb_setup_plane { | ||
86 | u8 plane; | ||
87 | u8 channel_out; | ||
88 | u32 offset; | ||
89 | u32 pos_x, pos_y; | ||
90 | u32 width, height; | ||
91 | u32 color_mode; | ||
92 | }; | ||
93 | |||
94 | struct omapfb_enable_plane { | ||
95 | u8 plane; | ||
96 | u8 enable; | ||
97 | }; | ||
98 | |||
99 | enum omapfb_color_key_type { | ||
100 | OMAPFB_COLOR_KEY_DISABLED = 0, | ||
101 | OMAPFB_COLOR_KEY_GFX_DST, | ||
102 | OMAPFB_COLOR_KEY_VID_SRC, | ||
103 | }; | ||
104 | |||
105 | struct omapfb_color_key { | ||
106 | u8 channel_out; | ||
107 | u32 background; | ||
108 | u32 trans_key; | ||
109 | u8 key_type; | ||
110 | }; | ||
111 | |||
112 | enum omapfb_update_mode { | ||
113 | OMAPFB_UPDATE_DISABLED = 0, | ||
114 | OMAPFB_AUTO_UPDATE, | ||
115 | OMAPFB_MANUAL_UPDATE | ||
116 | }; | ||
117 | |||
118 | #ifdef __KERNEL__ | ||
119 | |||
120 | #include <linux/completion.h> | ||
121 | #include <linux/interrupt.h> | ||
122 | #include <linux/fb.h> | ||
123 | |||
124 | #define OMAP_LCDC_INV_VSYNC 0x0001 | ||
125 | #define OMAP_LCDC_INV_HSYNC 0x0002 | ||
126 | #define OMAP_LCDC_INV_PIX_CLOCK 0x0004 | ||
127 | #define OMAP_LCDC_INV_OUTPUT_EN 0x0008 | ||
128 | #define OMAP_LCDC_HSVS_RISING_EDGE 0x0010 | ||
129 | #define OMAP_LCDC_HSVS_OPPOSITE 0x0020 | ||
130 | |||
131 | #define OMAP_LCDC_SIGNAL_MASK 0x003f | ||
132 | |||
133 | #define OMAP_LCDC_PANEL_TFT 0x0100 | ||
134 | |||
135 | #ifdef CONFIG_ARCH_OMAP1 | ||
136 | #define OMAPFB_PLANE_NUM 1 | ||
137 | #else | ||
138 | #define OMAPFB_PLANE_NUM 3 | ||
139 | #endif | ||
140 | |||
141 | struct omapfb_device; | ||
142 | |||
143 | struct lcd_panel { | ||
144 | const char *name; | ||
145 | int config; /* TFT/STN, signal inversion */ | ||
146 | int bpp; /* Pixel format in fb mem */ | ||
147 | int data_lines; /* Lines on LCD HW interface */ | ||
148 | |||
149 | int x_res, y_res; | ||
150 | int pixel_clock; /* In kHz */ | ||
151 | int hsw; /* Horizontal synchronization | ||
152 | pulse width */ | ||
153 | int hfp; /* Horizontal front porch */ | ||
154 | int hbp; /* Horizontal back porch */ | ||
155 | int vsw; /* Vertical synchronization | ||
156 | pulse width */ | ||
157 | int vfp; /* Vertical front porch */ | ||
158 | int vbp; /* Vertical back porch */ | ||
159 | int acb; /* ac-bias pin frequency */ | ||
160 | int pcd; /* pixel clock divider. | ||
161 | Obsolete use pixel_clock instead */ | ||
162 | |||
163 | int (*init) (struct omapfb_device *fbdev); | ||
164 | void (*cleanup) (void); | ||
165 | int (*enable) (void); | ||
166 | void (*disable) (void); | ||
167 | unsigned long (*get_caps) (void); | ||
168 | int (*set_bklight_level)(unsigned int level); | ||
169 | unsigned int (*get_bklight_level)(void); | ||
170 | unsigned int (*get_bklight_max) (void); | ||
171 | int (*run_test) (int test_num); | ||
172 | }; | ||
173 | |||
174 | struct omapfb_device; | ||
175 | |||
176 | struct extif_timings { | ||
177 | int cs_on_time; | ||
178 | int cs_off_time; | ||
179 | int we_on_time; | ||
180 | int we_off_time; | ||
181 | int re_on_time; | ||
182 | int re_off_time; | ||
183 | int we_cycle_time; | ||
184 | int re_cycle_time; | ||
185 | int cs_pulse_width; | ||
186 | int access_time; | ||
187 | }; | ||
188 | |||
189 | struct lcd_ctrl_extif { | ||
190 | int (*init) (void); | ||
191 | void (*cleanup) (void); | ||
192 | void (*set_timings) (const struct extif_timings *timings); | ||
193 | void (*write_command) (u32 cmd); | ||
194 | u32 (*read_data) (void); | ||
195 | void (*write_data) (u32 data); | ||
196 | void (*transfer_area) (int width, int height, | ||
197 | void (callback)(void * data), void *data); | ||
198 | }; | ||
199 | |||
200 | struct lcd_ctrl { | ||
201 | const char *name; | ||
202 | void *data; | ||
203 | |||
204 | int (*init) (struct omapfb_device *fbdev, | ||
205 | int ext_mode, int req_vram_size); | ||
206 | void (*cleanup) (void); | ||
207 | void (*get_vram_layout)(unsigned long *size, | ||
208 | void **virt_base, | ||
209 | dma_addr_t *phys_base); | ||
210 | unsigned long (*get_caps) (void); | ||
211 | int (*set_update_mode)(enum omapfb_update_mode mode); | ||
212 | enum omapfb_update_mode (*get_update_mode)(void); | ||
213 | int (*setup_plane) (int plane, int channel_out, | ||
214 | unsigned long offset, | ||
215 | int screen_width, | ||
216 | int pos_x, int pos_y, int width, | ||
217 | int height, int color_mode); | ||
218 | int (*enable_plane) (int plane, int enable); | ||
219 | int (*update_window) (struct omapfb_update_window *win, | ||
220 | void (*callback)(void *), | ||
221 | void *callback_data); | ||
222 | void (*sync) (void); | ||
223 | void (*suspend) (void); | ||
224 | void (*resume) (void); | ||
225 | int (*run_test) (int test_num); | ||
226 | int (*setcolreg) (u_int regno, u16 red, u16 green, | ||
227 | u16 blue, u16 transp, | ||
228 | int update_hw_mem); | ||
229 | int (*set_color_key) (struct omapfb_color_key *ck); | ||
230 | |||
231 | }; | ||
232 | |||
233 | enum omapfb_state { | ||
234 | OMAPFB_DISABLED = 0, | ||
235 | OMAPFB_SUSPENDED= 99, | ||
236 | OMAPFB_ACTIVE = 100 | ||
237 | }; | ||
238 | |||
239 | struct omapfb_device { | ||
240 | int state; | ||
241 | int ext_lcdc; /* Using external | ||
242 | LCD controller */ | ||
243 | struct semaphore rqueue_sema; | ||
244 | |||
245 | void *vram_virt_base; | ||
246 | dma_addr_t vram_phys_base; | ||
247 | unsigned long vram_size; | ||
248 | |||
249 | int color_mode; | ||
250 | int palette_size; | ||
251 | int mirror; | ||
252 | u32 pseudo_palette[17]; | ||
253 | |||
254 | struct lcd_panel *panel; /* LCD panel */ | ||
255 | struct lcd_ctrl *ctrl; /* LCD controller */ | ||
256 | struct lcd_ctrl *int_ctrl; /* internal LCD ctrl */ | ||
257 | struct lcd_ctrl_extif *ext_if; /* LCD ctrl external | ||
258 | interface */ | ||
259 | struct fb_info *fb_info; | ||
260 | |||
261 | struct device *dev; | ||
262 | }; | ||
263 | |||
264 | extern struct lcd_panel h3_panel; | ||
265 | extern struct lcd_panel h2_panel; | ||
266 | extern struct lcd_panel p2_panel; | ||
267 | extern struct lcd_panel osk_panel; | ||
268 | extern struct lcd_panel innovator1610_panel; | ||
269 | extern struct lcd_panel innovator1510_panel; | ||
270 | |||
271 | #ifdef CONFIG_ARCH_OMAP1 | ||
272 | extern struct lcd_ctrl omap1_lcd_ctrl; | ||
273 | #else | ||
274 | extern struct lcd_ctrl omap2_disp_ctrl; | ||
275 | #endif | ||
276 | |||
277 | extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval); | ||
278 | |||
279 | #endif /* __KERNEL__ */ | ||
280 | |||
281 | #endif /* __OMAPFB_H */ | ||
diff --git a/include/asm-arm/arch-omap/pm.h b/include/asm-arm/arch-omap/pm.h index fbd742d0c499..7c790425e363 100644 --- a/include/asm-arm/arch-omap/pm.h +++ b/include/asm-arm/arch-omap/pm.h | |||
@@ -98,7 +98,14 @@ | |||
98 | #define OMAP1610_IDLECT3 0xfffece24 | 98 | #define OMAP1610_IDLECT3 0xfffece24 |
99 | #define OMAP1610_IDLE_LOOP_REQUEST 0x0400 | 99 | #define OMAP1610_IDLE_LOOP_REQUEST 0x0400 |
100 | 100 | ||
101 | #if !defined(CONFIG_ARCH_OMAP1510) && \ | 101 | #define OMAP730_IDLECT1_SLEEP_VAL 0x16c7 |
102 | #define OMAP730_IDLECT2_SLEEP_VAL 0x09c7 | ||
103 | #define OMAP730_IDLECT3_VAL 0x3f | ||
104 | #define OMAP730_IDLECT3 0xfffece24 | ||
105 | #define OMAP730_IDLE_LOOP_REQUEST 0x0C00 | ||
106 | |||
107 | #if !defined(CONFIG_ARCH_OMAP730) && \ | ||
108 | !defined(CONFIG_ARCH_OMAP15XX) && \ | ||
102 | !defined(CONFIG_ARCH_OMAP16XX) && \ | 109 | !defined(CONFIG_ARCH_OMAP16XX) && \ |
103 | !defined(CONFIG_ARCH_OMAP24XX) | 110 | !defined(CONFIG_ARCH_OMAP24XX) |
104 | #error "Power management for this processor not implemented yet" | 111 | #error "Power management for this processor not implemented yet" |
@@ -107,8 +114,10 @@ | |||
107 | #ifndef __ASSEMBLER__ | 114 | #ifndef __ASSEMBLER__ |
108 | extern void omap_pm_idle(void); | 115 | extern void omap_pm_idle(void); |
109 | extern void omap_pm_suspend(void); | 116 | extern void omap_pm_suspend(void); |
117 | extern void omap730_cpu_suspend(unsigned short, unsigned short); | ||
110 | extern void omap1510_cpu_suspend(unsigned short, unsigned short); | 118 | extern void omap1510_cpu_suspend(unsigned short, unsigned short); |
111 | extern void omap1610_cpu_suspend(unsigned short, unsigned short); | 119 | extern void omap1610_cpu_suspend(unsigned short, unsigned short); |
120 | extern void omap730_idle_loop_suspend(void); | ||
112 | extern void omap1510_idle_loop_suspend(void); | 121 | extern void omap1510_idle_loop_suspend(void); |
113 | extern void omap1610_idle_loop_suspend(void); | 122 | extern void omap1610_idle_loop_suspend(void); |
114 | 123 | ||
@@ -118,6 +127,8 @@ extern void omap_serial_wake_trigger(int enable); | |||
118 | #define omap_serial_wake_trigger(x) {} | 127 | #define omap_serial_wake_trigger(x) {} |
119 | #endif /* CONFIG_OMAP_SERIAL_WAKE */ | 128 | #endif /* CONFIG_OMAP_SERIAL_WAKE */ |
120 | 129 | ||
130 | extern unsigned int omap730_cpu_suspend_sz; | ||
131 | extern unsigned int omap730_idle_loop_suspend_sz; | ||
121 | extern unsigned int omap1510_cpu_suspend_sz; | 132 | extern unsigned int omap1510_cpu_suspend_sz; |
122 | extern unsigned int omap1510_idle_loop_suspend_sz; | 133 | extern unsigned int omap1510_idle_loop_suspend_sz; |
123 | extern unsigned int omap1610_cpu_suspend_sz; | 134 | extern unsigned int omap1610_cpu_suspend_sz; |
@@ -131,6 +142,10 @@ extern unsigned int omap1610_idle_loop_suspend_sz; | |||
131 | #define ULPD_RESTORE(x) omap_writew((ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]), (x)) | 142 | #define ULPD_RESTORE(x) omap_writew((ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]), (x)) |
132 | #define ULPD_SHOW(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x] | 143 | #define ULPD_SHOW(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x] |
133 | 144 | ||
145 | #define MPUI730_SAVE(x) mpui730_sleep_save[MPUI730_SLEEP_SAVE_##x] = omap_readl(x) | ||
146 | #define MPUI730_RESTORE(x) omap_writel((mpui730_sleep_save[MPUI730_SLEEP_SAVE_##x]), (x)) | ||
147 | #define MPUI730_SHOW(x) mpui730_sleep_save[MPUI730_SLEEP_SAVE_##x] | ||
148 | |||
134 | #define MPUI1510_SAVE(x) mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x] = omap_readl(x) | 149 | #define MPUI1510_SAVE(x) mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x] = omap_readl(x) |
135 | #define MPUI1510_RESTORE(x) omap_writel((mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x]), (x)) | 150 | #define MPUI1510_RESTORE(x) omap_writel((mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x]), (x)) |
136 | #define MPUI1510_SHOW(x) mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x] | 151 | #define MPUI1510_SHOW(x) mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x] |
@@ -188,13 +203,34 @@ enum mpui1510_save_state { | |||
188 | MPUI1510_SLEEP_SAVE_EMIFS_CONFIG, | 203 | MPUI1510_SLEEP_SAVE_EMIFS_CONFIG, |
189 | MPUI1510_SLEEP_SAVE_OMAP_IH1_MIR, | 204 | MPUI1510_SLEEP_SAVE_OMAP_IH1_MIR, |
190 | MPUI1510_SLEEP_SAVE_OMAP_IH2_MIR, | 205 | MPUI1510_SLEEP_SAVE_OMAP_IH2_MIR, |
191 | #if defined(CONFIG_ARCH_OMAP1510) | 206 | #if defined(CONFIG_ARCH_OMAP15XX) |
192 | MPUI1510_SLEEP_SAVE_SIZE | 207 | MPUI1510_SLEEP_SAVE_SIZE |
193 | #else | 208 | #else |
194 | MPUI1510_SLEEP_SAVE_SIZE = 0 | 209 | MPUI1510_SLEEP_SAVE_SIZE = 0 |
195 | #endif | 210 | #endif |
196 | }; | 211 | }; |
197 | 212 | ||
213 | enum mpui730_save_state { | ||
214 | MPUI730_SLEEP_SAVE_START = 0, | ||
215 | /* | ||
216 | * MPUI registers 32 bits | ||
217 | */ | ||
218 | MPUI730_SLEEP_SAVE_MPUI_CTRL, | ||
219 | MPUI730_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG, | ||
220 | MPUI730_SLEEP_SAVE_MPUI_DSP_API_CONFIG, | ||
221 | MPUI730_SLEEP_SAVE_MPUI_DSP_STATUS, | ||
222 | MPUI730_SLEEP_SAVE_EMIFF_SDRAM_CONFIG, | ||
223 | MPUI730_SLEEP_SAVE_EMIFS_CONFIG, | ||
224 | MPUI730_SLEEP_SAVE_OMAP_IH1_MIR, | ||
225 | MPUI730_SLEEP_SAVE_OMAP_IH2_0_MIR, | ||
226 | MPUI730_SLEEP_SAVE_OMAP_IH2_1_MIR, | ||
227 | #if defined(CONFIG_ARCH_OMAP730) | ||
228 | MPUI730_SLEEP_SAVE_SIZE | ||
229 | #else | ||
230 | MPUI730_SLEEP_SAVE_SIZE = 0 | ||
231 | #endif | ||
232 | }; | ||
233 | |||
198 | enum mpui1610_save_state { | 234 | enum mpui1610_save_state { |
199 | MPUI1610_SLEEP_SAVE_START = 0, | 235 | MPUI1610_SLEEP_SAVE_START = 0, |
200 | /* | 236 | /* |
diff --git a/include/asm-arm/arch-omap/prcm.h b/include/asm-arm/arch-omap/prcm.h new file mode 100644 index 000000000000..7b48a5cbb15f --- /dev/null +++ b/include/asm-arm/arch-omap/prcm.h | |||
@@ -0,0 +1,429 @@ | |||
1 | /* | ||
2 | * prcm.h - Access definations for use in OMAP24XX clock and power management | ||
3 | * | ||
4 | * Copyright (C) 2005 Texas Instruments, Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #ifndef __ASM_ARM_ARCH_DPM_PRCM_H | ||
22 | #define __ASM_ARM_ARCH_DPM_PRCM_H | ||
23 | |||
24 | /* SET_PERFORMANCE_LEVEL PARAMETERS */ | ||
25 | #define PRCM_HALF_SPEED 1 | ||
26 | #define PRCM_FULL_SPEED 2 | ||
27 | |||
28 | #ifndef __ASSEMBLER__ | ||
29 | |||
30 | #define PRCM_REG32(offset) __REG32(OMAP24XX_PRCM_BASE + (offset)) | ||
31 | |||
32 | #define PRCM_REVISION PRCM_REG32(0x000) | ||
33 | #define PRCM_SYSCONFIG PRCM_REG32(0x010) | ||
34 | #define PRCM_IRQSTATUS_MPU PRCM_REG32(0x018) | ||
35 | #define PRCM_IRQENABLE_MPU PRCM_REG32(0x01C) | ||
36 | #define PRCM_VOLTCTRL PRCM_REG32(0x050) | ||
37 | #define PRCM_VOLTST PRCM_REG32(0x054) | ||
38 | #define PRCM_CLKSRC_CTRL PRCM_REG32(0x060) | ||
39 | #define PRCM_CLKOUT_CTRL PRCM_REG32(0x070) | ||
40 | #define PRCM_CLKEMUL_CTRL PRCM_REG32(0x078) | ||
41 | #define PRCM_CLKCFG_CTRL PRCM_REG32(0x080) | ||
42 | #define PRCM_CLKCFG_STATUS PRCM_REG32(0x084) | ||
43 | #define PRCM_VOLTSETUP PRCM_REG32(0x090) | ||
44 | #define PRCM_CLKSSETUP PRCM_REG32(0x094) | ||
45 | #define PRCM_POLCTRL PRCM_REG32(0x098) | ||
46 | |||
47 | /* GENERAL PURPOSE */ | ||
48 | #define GENERAL_PURPOSE1 PRCM_REG32(0x0B0) | ||
49 | #define GENERAL_PURPOSE2 PRCM_REG32(0x0B4) | ||
50 | #define GENERAL_PURPOSE3 PRCM_REG32(0x0B8) | ||
51 | #define GENERAL_PURPOSE4 PRCM_REG32(0x0BC) | ||
52 | #define GENERAL_PURPOSE5 PRCM_REG32(0x0C0) | ||
53 | #define GENERAL_PURPOSE6 PRCM_REG32(0x0C4) | ||
54 | #define GENERAL_PURPOSE7 PRCM_REG32(0x0C8) | ||
55 | #define GENERAL_PURPOSE8 PRCM_REG32(0x0CC) | ||
56 | #define GENERAL_PURPOSE9 PRCM_REG32(0x0D0) | ||
57 | #define GENERAL_PURPOSE10 PRCM_REG32(0x0D4) | ||
58 | #define GENERAL_PURPOSE11 PRCM_REG32(0x0D8) | ||
59 | #define GENERAL_PURPOSE12 PRCM_REG32(0x0DC) | ||
60 | #define GENERAL_PURPOSE13 PRCM_REG32(0x0E0) | ||
61 | #define GENERAL_PURPOSE14 PRCM_REG32(0x0E4) | ||
62 | #define GENERAL_PURPOSE15 PRCM_REG32(0x0E8) | ||
63 | #define GENERAL_PURPOSE16 PRCM_REG32(0x0EC) | ||
64 | #define GENERAL_PURPOSE17 PRCM_REG32(0x0F0) | ||
65 | #define GENERAL_PURPOSE18 PRCM_REG32(0x0F4) | ||
66 | #define GENERAL_PURPOSE19 PRCM_REG32(0x0F8) | ||
67 | #define GENERAL_PURPOSE20 PRCM_REG32(0x0FC) | ||
68 | |||
69 | /* MPU */ | ||
70 | #define CM_CLKSEL_MPU PRCM_REG32(0x140) | ||
71 | #define CM_CLKSTCTRL_MPU PRCM_REG32(0x148) | ||
72 | #define RM_RSTST_MPU PRCM_REG32(0x158) | ||
73 | #define PM_WKDEP_MPU PRCM_REG32(0x1C8) | ||
74 | #define PM_EVGENCTRL_MPU PRCM_REG32(0x1D4) | ||
75 | #define PM_EVEGENONTIM_MPU PRCM_REG32(0x1D8) | ||
76 | #define PM_EVEGENOFFTIM_MPU PRCM_REG32(0x1DC) | ||
77 | #define PM_PWSTCTRL_MPU PRCM_REG32(0x1E0) | ||
78 | #define PM_PWSTST_MPU PRCM_REG32(0x1E4) | ||
79 | |||
80 | /* CORE */ | ||
81 | #define CM_FCLKEN1_CORE PRCM_REG32(0x200) | ||
82 | #define CM_FCLKEN2_CORE PRCM_REG32(0x204) | ||
83 | #define CM_FCLKEN3_CORE PRCM_REG32(0x208) | ||
84 | #define CM_ICLKEN1_CORE PRCM_REG32(0x210) | ||
85 | #define CM_ICLKEN2_CORE PRCM_REG32(0x214) | ||
86 | #define CM_ICLKEN3_CORE PRCM_REG32(0x218) | ||
87 | #define CM_ICLKEN4_CORE PRCM_REG32(0x21C) | ||
88 | #define CM_IDLEST1_CORE PRCM_REG32(0x220) | ||
89 | #define CM_IDLEST2_CORE PRCM_REG32(0x224) | ||
90 | #define CM_IDLEST3_CORE PRCM_REG32(0x228) | ||
91 | #define CM_IDLEST4_CORE PRCM_REG32(0x22C) | ||
92 | #define CM_AUTOIDLE1_CORE PRCM_REG32(0x230) | ||
93 | #define CM_AUTOIDLE2_CORE PRCM_REG32(0x234) | ||
94 | #define CM_AUTOIDLE3_CORE PRCM_REG32(0x238) | ||
95 | #define CM_AUTOIDLE4_CORE PRCM_REG32(0x23C) | ||
96 | #define CM_CLKSEL1_CORE PRCM_REG32(0x240) | ||
97 | #define CM_CLKSEL2_CORE PRCM_REG32(0x244) | ||
98 | #define CM_CLKSTCTRL_CORE PRCM_REG32(0x248) | ||
99 | #define PM_WKEN1_CORE PRCM_REG32(0x2A0) | ||
100 | #define PM_WKEN2_CORE PRCM_REG32(0x2A4) | ||
101 | #define PM_WKST1_CORE PRCM_REG32(0x2B0) | ||
102 | #define PM_WKST2_CORE PRCM_REG32(0x2B4) | ||
103 | #define PM_WKDEP_CORE PRCM_REG32(0x2C8) | ||
104 | #define PM_PWSTCTRL_CORE PRCM_REG32(0x2E0) | ||
105 | #define PM_PWSTST_CORE PRCM_REG32(0x2E4) | ||
106 | |||
107 | /* GFX */ | ||
108 | #define CM_FCLKEN_GFX PRCM_REG32(0x300) | ||
109 | #define CM_ICLKEN_GFX PRCM_REG32(0x310) | ||
110 | #define CM_IDLEST_GFX PRCM_REG32(0x320) | ||
111 | #define CM_CLKSEL_GFX PRCM_REG32(0x340) | ||
112 | #define CM_CLKSTCTRL_GFX PRCM_REG32(0x348) | ||
113 | #define RM_RSTCTRL_GFX PRCM_REG32(0x350) | ||
114 | #define RM_RSTST_GFX PRCM_REG32(0x358) | ||
115 | #define PM_WKDEP_GFX PRCM_REG32(0x3C8) | ||
116 | #define PM_PWSTCTRL_GFX PRCM_REG32(0x3E0) | ||
117 | #define PM_PWSTST_GFX PRCM_REG32(0x3E4) | ||
118 | |||
119 | /* WAKE-UP */ | ||
120 | #define CM_FCLKEN_WKUP PRCM_REG32(0x400) | ||
121 | #define CM_ICLKEN_WKUP PRCM_REG32(0x410) | ||
122 | #define CM_IDLEST_WKUP PRCM_REG32(0x420) | ||
123 | #define CM_AUTOIDLE_WKUP PRCM_REG32(0x430) | ||
124 | #define CM_CLKSEL_WKUP PRCM_REG32(0x440) | ||
125 | #define RM_RSTCTRL_WKUP PRCM_REG32(0x450) | ||
126 | #define RM_RSTTIME_WKUP PRCM_REG32(0x454) | ||
127 | #define RM_RSTST_WKUP PRCM_REG32(0x458) | ||
128 | #define PM_WKEN_WKUP PRCM_REG32(0x4A0) | ||
129 | #define PM_WKST_WKUP PRCM_REG32(0x4B0) | ||
130 | |||
131 | /* CLOCKS */ | ||
132 | #define CM_CLKEN_PLL PRCM_REG32(0x500) | ||
133 | #define CM_IDLEST_CKGEN PRCM_REG32(0x520) | ||
134 | #define CM_AUTOIDLE_PLL PRCM_REG32(0x530) | ||
135 | #define CM_CLKSEL1_PLL PRCM_REG32(0x540) | ||
136 | #define CM_CLKSEL2_PLL PRCM_REG32(0x544) | ||
137 | |||
138 | /* DSP */ | ||
139 | #define CM_FCLKEN_DSP PRCM_REG32(0x800) | ||
140 | #define CM_ICLKEN_DSP PRCM_REG32(0x810) | ||
141 | #define CM_IDLEST_DSP PRCM_REG32(0x820) | ||
142 | #define CM_AUTOIDLE_DSP PRCM_REG32(0x830) | ||
143 | #define CM_CLKSEL_DSP PRCM_REG32(0x840) | ||
144 | #define CM_CLKSTCTRL_DSP PRCM_REG32(0x848) | ||
145 | #define RM_RSTCTRL_DSP PRCM_REG32(0x850) | ||
146 | #define RM_RSTST_DSP PRCM_REG32(0x858) | ||
147 | #define PM_WKEN_DSP PRCM_REG32(0x8A0) | ||
148 | #define PM_WKDEP_DSP PRCM_REG32(0x8C8) | ||
149 | #define PM_PWSTCTRL_DSP PRCM_REG32(0x8E0) | ||
150 | #define PM_PWSTST_DSP PRCM_REG32(0x8E4) | ||
151 | #define PRCM_IRQSTATUS_DSP PRCM_REG32(0x8F0) | ||
152 | #define PRCM_IRQENABLE_DSP PRCM_REG32(0x8F4) | ||
153 | |||
154 | /* IVA */ | ||
155 | #define PRCM_IRQSTATUS_IVA PRCM_REG32(0x8F8) | ||
156 | #define PRCM_IRQENABLE_IVA PRCM_REG32(0x8FC) | ||
157 | |||
158 | /* Modem on 2430 */ | ||
159 | #define CM_FCLKEN_MDM PRCM_REG32(0xC00) | ||
160 | #define CM_ICLKEN_MDM PRCM_REG32(0xC10) | ||
161 | #define CM_IDLEST_MDM PRCM_REG32(0xC20) | ||
162 | #define CM_CLKSEL_MDM PRCM_REG32(0xC40) | ||
163 | |||
164 | /* FIXME: Move to header for 2430 */ | ||
165 | #define DISP_BASE (OMAP24XX_L4_IO_BASE+0x50000) | ||
166 | #define DISP_REG32(offset) __REG32(DISP_BASE + (offset)) | ||
167 | |||
168 | #define OMAP24XX_GPMC_BASE (L3_24XX_BASE + 0xa000) | ||
169 | #define GPMC_BASE (OMAP24XX_GPMC_BASE) | ||
170 | #define GPMC_REG32(offset) __REG32(GPMC_BASE + (offset)) | ||
171 | |||
172 | #define GPT1_BASE (OMAP24XX_GPT1) | ||
173 | #define GPT1_REG32(offset) __REG32(GPT1_BASE + (offset)) | ||
174 | |||
175 | /* Misc sysconfig */ | ||
176 | #define DISPC_SYSCONFIG DISP_REG32(0x410) | ||
177 | #define SPI_BASE (OMAP24XX_L4_IO_BASE+0x98000) | ||
178 | #define MCSPI1_SYSCONFIG __REG32(SPI_BASE + 0x10) | ||
179 | #define MCSPI2_SYSCONFIG __REG32(SPI_BASE+0x2000 + 0x10) | ||
180 | |||
181 | //#define DSP_MMU_SYSCONFIG 0x5A000010 | ||
182 | #define CAMERA_MMU_SYSCONFIG __REG32(DISP_BASE+0x2C10) | ||
183 | //#define IVA_MMU_SYSCONFIG 0x5D000010 | ||
184 | //#define DSP_DMA_SYSCONFIG 0x00FCC02C | ||
185 | #define CAMERA_DMA_SYSCONFIG __REG32(DISP_BASE+0x282C) | ||
186 | #define SYSTEM_DMA_SYSCONFIG __REG32(DISP_BASE+0x602C) | ||
187 | #define GPMC_SYSCONFIG GPMC_REG32(0x010) | ||
188 | #define MAILBOXES_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x94010) | ||
189 | #define UART1_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6A054) | ||
190 | #define UART2_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6C054) | ||
191 | #define UART3_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6E054) | ||
192 | //#define IVA_SYSCONFIG 0x5C060010 | ||
193 | #define SDRC_SYSCONFIG __REG32(OMAP24XX_SDRC_BASE+0x10) | ||
194 | #define SMS_SYSCONFIG __REG32(OMAP24XX_SMS_BASE+0x10) | ||
195 | #define SSI_SYSCONFIG __REG32(DISP_BASE+0x8010) | ||
196 | //#define VLYNQ_SYSCONFIG 0x67FFFE10 | ||
197 | |||
198 | /* rkw - good cannidates for PM_ to start what nm was trying */ | ||
199 | #define OMAP24XX_GPT2 (OMAP24XX_L4_IO_BASE+0x2A000) | ||
200 | #define OMAP24XX_GPT3 (OMAP24XX_L4_IO_BASE+0x78000) | ||
201 | #define OMAP24XX_GPT4 (OMAP24XX_L4_IO_BASE+0x7A000) | ||
202 | #define OMAP24XX_GPT5 (OMAP24XX_L4_IO_BASE+0x7C000) | ||
203 | #define OMAP24XX_GPT6 (OMAP24XX_L4_IO_BASE+0x7E000) | ||
204 | #define OMAP24XX_GPT7 (OMAP24XX_L4_IO_BASE+0x80000) | ||
205 | #define OMAP24XX_GPT8 (OMAP24XX_L4_IO_BASE+0x82000) | ||
206 | #define OMAP24XX_GPT9 (OMAP24XX_L4_IO_BASE+0x84000) | ||
207 | #define OMAP24XX_GPT10 (OMAP24XX_L4_IO_BASE+0x86000) | ||
208 | #define OMAP24XX_GPT11 (OMAP24XX_L4_IO_BASE+0x88000) | ||
209 | #define OMAP24XX_GPT12 (OMAP24XX_L4_IO_BASE+0x8A000) | ||
210 | |||
211 | #define GPTIMER1_SYSCONFIG GPT1_REG32(0x010) | ||
212 | #define GPTIMER2_SYSCONFIG __REG32(OMAP24XX_GPT2 + 0x10) | ||
213 | #define GPTIMER3_SYSCONFIG __REG32(OMAP24XX_GPT3 + 0x10) | ||
214 | #define GPTIMER4_SYSCONFIG __REG32(OMAP24XX_GPT4 + 0x10) | ||
215 | #define GPTIMER5_SYSCONFIG __REG32(OMAP24XX_GPT5 + 0x10) | ||
216 | #define GPTIMER6_SYSCONFIG __REG32(OMAP24XX_GPT6 + 0x10) | ||
217 | #define GPTIMER7_SYSCONFIG __REG32(OMAP24XX_GPT7 + 0x10) | ||
218 | #define GPTIMER8_SYSCONFIG __REG32(OMAP24XX_GPT8 + 0x10) | ||
219 | #define GPTIMER9_SYSCONFIG __REG32(OMAP24XX_GPT9 + 0x10) | ||
220 | #define GPTIMER10_SYSCONFIG __REG32(OMAP24XX_GPT10 + 0x10) | ||
221 | #define GPTIMER11_SYSCONFIG __REG32(OMAP24XX_GPT11 + 0x10) | ||
222 | #define GPTIMER12_SYSCONFIG __REG32(OMAP24XX_GPT12 + 0x10) | ||
223 | |||
224 | #define GPIOX_BASE(X) (OMAP24XX_GPIO_BASE+(0x2000*((X)-1))) | ||
225 | |||
226 | #define GPIO1_SYSCONFIG __REG32((GPIOX_BASE(1)+0x10)) | ||
227 | #define GPIO2_SYSCONFIG __REG32((GPIOX_BASE(2)+0x10)) | ||
228 | #define GPIO3_SYSCONFIG __REG32((GPIOX_BASE(3)+0x10)) | ||
229 | #define GPIO4_SYSCONFIG __REG32((GPIOX_BASE(4)+0x10)) | ||
230 | |||
231 | /* GP TIMER 1 */ | ||
232 | #define GPTIMER1_TISTAT GPT1_REG32(0x014) | ||
233 | #define GPTIMER1_TISR GPT1_REG32(0x018) | ||
234 | #define GPTIMER1_TIER GPT1_REG32(0x01C) | ||
235 | #define GPTIMER1_TWER GPT1_REG32(0x020) | ||
236 | #define GPTIMER1_TCLR GPT1_REG32(0x024) | ||
237 | #define GPTIMER1_TCRR GPT1_REG32(0x028) | ||
238 | #define GPTIMER1_TLDR GPT1_REG32(0x02C) | ||
239 | #define GPTIMER1_TTGR GPT1_REG32(0x030) | ||
240 | #define GPTIMER1_TWPS GPT1_REG32(0x034) | ||
241 | #define GPTIMER1_TMAR GPT1_REG32(0x038) | ||
242 | #define GPTIMER1_TCAR1 GPT1_REG32(0x03C) | ||
243 | #define GPTIMER1_TSICR GPT1_REG32(0x040) | ||
244 | #define GPTIMER1_TCAR2 GPT1_REG32(0x044) | ||
245 | |||
246 | /* rkw -- base fix up please... */ | ||
247 | #define GPTIMER3_TISR __REG32(OMAP24XX_L4_IO_BASE+0x78018) | ||
248 | |||
249 | /* SDRC */ | ||
250 | #define SDRC_DLLA_CTRL __REG32(OMAP24XX_SDRC_BASE+0x060) | ||
251 | #define SDRC_DLLA_STATUS __REG32(OMAP24XX_SDRC_BASE+0x064) | ||
252 | #define SDRC_DLLB_CTRL __REG32(OMAP24XX_SDRC_BASE+0x068) | ||
253 | #define SDRC_DLLB_STATUS __REG32(OMAP24XX_SDRC_BASE+0x06C) | ||
254 | #define SDRC_POWER __REG32(OMAP24XX_SDRC_BASE+0x070) | ||
255 | #define SDRC_MR_0 __REG32(OMAP24XX_SDRC_BASE+0x084) | ||
256 | |||
257 | /* GPIO 1 */ | ||
258 | #define GPIO1_BASE GPIOX_BASE(1) | ||
259 | #define GPIO1_REG32(offset) __REG32(GPIO1_BASE + (offset)) | ||
260 | #define GPIO1_IRQENABLE1 GPIO1_REG32(0x01C) | ||
261 | #define GPIO1_IRQSTATUS1 GPIO1_REG32(0x018) | ||
262 | #define GPIO1_IRQENABLE2 GPIO1_REG32(0x02C) | ||
263 | #define GPIO1_IRQSTATUS2 GPIO1_REG32(0x028) | ||
264 | #define GPIO1_WAKEUPENABLE GPIO1_REG32(0x020) | ||
265 | #define GPIO1_RISINGDETECT GPIO1_REG32(0x048) | ||
266 | #define GPIO1_DATAIN GPIO1_REG32(0x038) | ||
267 | #define GPIO1_OE GPIO1_REG32(0x034) | ||
268 | #define GPIO1_DATAOUT GPIO1_REG32(0x03C) | ||
269 | |||
270 | /* GPIO2 */ | ||
271 | #define GPIO2_BASE GPIOX_BASE(2) | ||
272 | #define GPIO2_REG32(offset) __REG32(GPIO2_BASE + (offset)) | ||
273 | #define GPIO2_IRQENABLE1 GPIO2_REG32(0x01C) | ||
274 | #define GPIO2_IRQSTATUS1 GPIO2_REG32(0x018) | ||
275 | #define GPIO2_IRQENABLE2 GPIO2_REG32(0x02C) | ||
276 | #define GPIO2_IRQSTATUS2 GPIO2_REG32(0x028) | ||
277 | #define GPIO2_WAKEUPENABLE GPIO2_REG32(0x020) | ||
278 | #define GPIO2_RISINGDETECT GPIO2_REG32(0x048) | ||
279 | #define GPIO2_DATAIN GPIO2_REG32(0x038) | ||
280 | #define GPIO2_OE GPIO2_REG32(0x034) | ||
281 | #define GPIO2_DATAOUT GPIO2_REG32(0x03C) | ||
282 | |||
283 | /* GPIO 3 */ | ||
284 | #define GPIO3_BASE GPIOX_BASE(3) | ||
285 | #define GPIO3_REG32(offset) __REG32(GPIO3_BASE + (offset)) | ||
286 | #define GPIO3_IRQENABLE1 GPIO3_REG32(0x01C) | ||
287 | #define GPIO3_IRQSTATUS1 GPIO3_REG32(0x018) | ||
288 | #define GPIO3_IRQENABLE2 GPIO3_REG32(0x02C) | ||
289 | #define GPIO3_IRQSTATUS2 GPIO3_REG32(0x028) | ||
290 | #define GPIO3_WAKEUPENABLE GPIO3_REG32(0x020) | ||
291 | #define GPIO3_RISINGDETECT GPIO3_REG32(0x048) | ||
292 | #define GPIO3_FALLINGDETECT GPIO3_REG32(0x04C) | ||
293 | #define GPIO3_DATAIN GPIO3_REG32(0x038) | ||
294 | #define GPIO3_OE GPIO3_REG32(0x034) | ||
295 | #define GPIO3_DATAOUT GPIO3_REG32(0x03C) | ||
296 | #define GPIO3_DEBOUNCENABLE GPIO3_REG32(0x050) | ||
297 | #define GPIO3_DEBOUNCINGTIME GPIO3_REG32(0x054) | ||
298 | |||
299 | /* GPIO 4 */ | ||
300 | #define GPIO4_BASE GPIOX_BASE(4) | ||
301 | #define GPIO4_REG32(offset) __REG32(GPIO4_BASE + (offset)) | ||
302 | #define GPIO4_IRQENABLE1 GPIO4_REG32(0x01C) | ||
303 | #define GPIO4_IRQSTATUS1 GPIO4_REG32(0x018) | ||
304 | #define GPIO4_IRQENABLE2 GPIO4_REG32(0x02C) | ||
305 | #define GPIO4_IRQSTATUS2 GPIO4_REG32(0x028) | ||
306 | #define GPIO4_WAKEUPENABLE GPIO4_REG32(0x020) | ||
307 | #define GPIO4_RISINGDETECT GPIO4_REG32(0x048) | ||
308 | #define GPIO4_FALLINGDETECT GPIO4_REG32(0x04C) | ||
309 | #define GPIO4_DATAIN GPIO4_REG32(0x038) | ||
310 | #define GPIO4_OE GPIO4_REG32(0x034) | ||
311 | #define GPIO4_DATAOUT GPIO4_REG32(0x03C) | ||
312 | #define GPIO4_DEBOUNCENABLE GPIO4_REG32(0x050) | ||
313 | #define GPIO4_DEBOUNCINGTIME GPIO4_REG32(0x054) | ||
314 | |||
315 | |||
316 | /* IO CONFIG */ | ||
317 | #define CONTROL_BASE (OMAP24XX_CTRL_BASE) | ||
318 | #define CONTROL_REG32(offset) __REG32(CONTROL_BASE + (offset)) | ||
319 | |||
320 | #define CONTROL_PADCONF_SPI1_NCS2 CONTROL_REG32(0x104) | ||
321 | #define CONTROL_PADCONF_SYS_XTALOUT CONTROL_REG32(0x134) | ||
322 | #define CONTROL_PADCONF_UART1_RX CONTROL_REG32(0x0C8) | ||
323 | #define CONTROL_PADCONF_MCBSP1_DX CONTROL_REG32(0x10C) | ||
324 | #define CONTROL_PADCONF_GPMC_NCS4 CONTROL_REG32(0x090) | ||
325 | #define CONTROL_PADCONF_DSS_D5 CONTROL_REG32(0x0B8) | ||
326 | #define CONTROL_PADCONF_DSS_D9 CONTROL_REG32(0x0BC) | ||
327 | #define CONTROL_PADCONF_DSS_D13 CONTROL_REG32(0x0C0) | ||
328 | #define CONTROL_PADCONF_DSS_VSYNC CONTROL_REG32(0x0CC) | ||
329 | |||
330 | /* CONTROL */ | ||
331 | #define CONTROL_DEVCONF CONTROL_REG32(0x274) | ||
332 | |||
333 | /* INTERRUPT CONTROLLER */ | ||
334 | #define INTC_BASE (OMAP24XX_L4_IO_BASE+0xfe000) | ||
335 | #define INTC_REG32(offset) __REG32(INTC_BASE + (offset)) | ||
336 | |||
337 | #define INTC1_U_BASE INTC_REG32(0x000) | ||
338 | #define INTC_MIR0 INTC_REG32(0x084) | ||
339 | #define INTC_MIR_SET0 INTC_REG32(0x08C) | ||
340 | #define INTC_MIR_CLEAR0 INTC_REG32(0x088) | ||
341 | #define INTC_ISR_CLEAR0 INTC_REG32(0x094) | ||
342 | #define INTC_MIR1 INTC_REG32(0x0A4) | ||
343 | #define INTC_MIR_SET1 INTC_REG32(0x0AC) | ||
344 | #define INTC_MIR_CLEAR1 INTC_REG32(0x0A8) | ||
345 | #define INTC_ISR_CLEAR1 INTC_REG32(0x0B4) | ||
346 | #define INTC_MIR2 INTC_REG32(0x0C4) | ||
347 | #define INTC_MIR_SET2 INTC_REG32(0x0CC) | ||
348 | #define INTC_MIR_CLEAR2 INTC_REG32(0x0C8) | ||
349 | #define INTC_ISR_CLEAR2 INTC_REG32(0x0D4) | ||
350 | #define INTC_SIR_IRQ INTC_REG32(0x040) | ||
351 | #define INTC_CONTROL INTC_REG32(0x048) | ||
352 | #define INTC_ILR11 INTC_REG32(0x12C) | ||
353 | #define INTC_ILR32 INTC_REG32(0x180) | ||
354 | #define INTC_ILR37 INTC_REG32(0x194) | ||
355 | #define INTC_SYSCONFIG INTC_REG32(0x010) | ||
356 | |||
357 | /* RAM FIREWALL */ | ||
358 | #define RAMFW_BASE (0x68005000) | ||
359 | #define RAMFW_REG32(offset) __REG32(RAMFW_BASE + (offset)) | ||
360 | |||
361 | #define RAMFW_REQINFOPERM0 RAMFW_REG32(0x048) | ||
362 | #define RAMFW_READPERM0 RAMFW_REG32(0x050) | ||
363 | #define RAMFW_WRITEPERM0 RAMFW_REG32(0x058) | ||
364 | |||
365 | /* GPMC CS1 FPGA ON USER INTERFACE MODULE */ | ||
366 | //#define DEBUG_BOARD_LED_REGISTER 0x04000014 | ||
367 | |||
368 | /* GPMC CS0 */ | ||
369 | #define GPMC_CONFIG1_0 GPMC_REG32(0x060) | ||
370 | #define GPMC_CONFIG2_0 GPMC_REG32(0x064) | ||
371 | #define GPMC_CONFIG3_0 GPMC_REG32(0x068) | ||
372 | #define GPMC_CONFIG4_0 GPMC_REG32(0x06C) | ||
373 | #define GPMC_CONFIG5_0 GPMC_REG32(0x070) | ||
374 | #define GPMC_CONFIG6_0 GPMC_REG32(0x074) | ||
375 | #define GPMC_CONFIG7_0 GPMC_REG32(0x078) | ||
376 | |||
377 | /* GPMC CS1 */ | ||
378 | #define GPMC_CONFIG1_1 GPMC_REG32(0x090) | ||
379 | #define GPMC_CONFIG2_1 GPMC_REG32(0x094) | ||
380 | #define GPMC_CONFIG3_1 GPMC_REG32(0x098) | ||
381 | #define GPMC_CONFIG4_1 GPMC_REG32(0x09C) | ||
382 | #define GPMC_CONFIG5_1 GPMC_REG32(0x0a0) | ||
383 | #define GPMC_CONFIG6_1 GPMC_REG32(0x0a4) | ||
384 | #define GPMC_CONFIG7_1 GPMC_REG32(0x0a8) | ||
385 | |||
386 | /* DSS */ | ||
387 | #define DSS_CONTROL DISP_REG32(0x040) | ||
388 | #define DISPC_CONTROL DISP_REG32(0x440) | ||
389 | #define DISPC_SYSSTATUS DISP_REG32(0x414) | ||
390 | #define DISPC_IRQSTATUS DISP_REG32(0x418) | ||
391 | #define DISPC_IRQENABLE DISP_REG32(0x41C) | ||
392 | #define DISPC_CONFIG DISP_REG32(0x444) | ||
393 | #define DISPC_DEFAULT_COLOR0 DISP_REG32(0x44C) | ||
394 | #define DISPC_DEFAULT_COLOR1 DISP_REG32(0x450) | ||
395 | #define DISPC_TRANS_COLOR0 DISP_REG32(0x454) | ||
396 | #define DISPC_TRANS_COLOR1 DISP_REG32(0x458) | ||
397 | #define DISPC_LINE_NUMBER DISP_REG32(0x460) | ||
398 | #define DISPC_TIMING_H DISP_REG32(0x464) | ||
399 | #define DISPC_TIMING_V DISP_REG32(0x468) | ||
400 | #define DISPC_POL_FREQ DISP_REG32(0x46C) | ||
401 | #define DISPC_DIVISOR DISP_REG32(0x470) | ||
402 | #define DISPC_SIZE_DIG DISP_REG32(0x478) | ||
403 | #define DISPC_SIZE_LCD DISP_REG32(0x47C) | ||
404 | #define DISPC_GFX_BA0 DISP_REG32(0x480) | ||
405 | #define DISPC_GFX_BA1 DISP_REG32(0x484) | ||
406 | #define DISPC_GFX_POSITION DISP_REG32(0x488) | ||
407 | #define DISPC_GFX_SIZE DISP_REG32(0x48C) | ||
408 | #define DISPC_GFX_ATTRIBUTES DISP_REG32(0x4A0) | ||
409 | #define DISPC_GFX_FIFO_THRESHOLD DISP_REG32(0x4A4) | ||
410 | #define DISPC_GFX_ROW_INC DISP_REG32(0x4AC) | ||
411 | #define DISPC_GFX_PIXEL_INC DISP_REG32(0x4B0) | ||
412 | #define DISPC_GFX_WINDOW_SKIP DISP_REG32(0x4B4) | ||
413 | #define DISPC_GFX_TABLE_BA DISP_REG32(0x4B8) | ||
414 | #define DISPC_DATA_CYCLE1 DISP_REG32(0x5D4) | ||
415 | #define DISPC_DATA_CYCLE2 DISP_REG32(0x5D8) | ||
416 | #define DISPC_DATA_CYCLE3 DISP_REG32(0x5DC) | ||
417 | |||
418 | /* Wake up define for board */ | ||
419 | #define GPIO97 (1 << 1) | ||
420 | #define GPIO88 (1 << 24) | ||
421 | |||
422 | #endif /* __ASSEMBLER__ */ | ||
423 | |||
424 | #endif | ||
425 | |||
426 | |||
427 | |||
428 | |||
429 | |||
diff --git a/include/asm-arm/arch-omap/sram.h b/include/asm-arm/arch-omap/sram.h new file mode 100644 index 000000000000..e72ccbf0fe06 --- /dev/null +++ b/include/asm-arm/arch-omap/sram.h | |||
@@ -0,0 +1,38 @@ | |||
1 | /* | ||
2 | * linux/include/asm-arm/arch-omap/sram.h | ||
3 | * | ||
4 | * Interface for functions that need to be run in internal SRAM | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #ifndef __ARCH_ARM_OMAP_SRAM_H | ||
12 | #define __ARCH_ARM_OMAP_SRAM_H | ||
13 | |||
14 | extern void * omap_sram_push(void * start, unsigned long size); | ||
15 | extern void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl); | ||
16 | |||
17 | extern void omap2_sram_ddr_init(u32 *slow_dll_ctrl, u32 fast_dll_ctrl, | ||
18 | u32 base_cs, u32 force_unlock); | ||
19 | extern void omap2_sram_reprogram_sdrc(u32 perf_level, u32 dll_val, | ||
20 | u32 mem_type); | ||
21 | extern u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass); | ||
22 | |||
23 | |||
24 | /* Do not use these */ | ||
25 | extern void sram_reprogram_clock(u32 ckctl, u32 dpllctl); | ||
26 | extern unsigned long sram_reprogram_clock_sz; | ||
27 | |||
28 | extern void sram_ddr_init(u32 *slow_dll_ctrl, u32 fast_dll_ctrl, | ||
29 | u32 base_cs, u32 force_unlock); | ||
30 | extern unsigned long sram_ddr_init_sz; | ||
31 | |||
32 | extern u32 sram_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass); | ||
33 | extern unsigned long sram_set_prcm_sz; | ||
34 | |||
35 | extern void sram_reprogram_sdrc(u32 perf_level, u32 dll_val, u32 mem_type); | ||
36 | extern unsigned long sram_reprogram_sdrc_sz; | ||
37 | |||
38 | #endif | ||
diff --git a/include/asm-arm/arch-omap/system.h b/include/asm-arm/arch-omap/system.h index ff37bc27e603..b43cdd2a3874 100644 --- a/include/asm-arm/arch-omap/system.h +++ b/include/asm-arm/arch-omap/system.h | |||
@@ -6,18 +6,21 @@ | |||
6 | #define __ASM_ARCH_SYSTEM_H | 6 | #define __ASM_ARCH_SYSTEM_H |
7 | #include <linux/config.h> | 7 | #include <linux/config.h> |
8 | #include <asm/mach-types.h> | 8 | #include <asm/mach-types.h> |
9 | #include <asm/hardware/clock.h> | ||
9 | #include <asm/arch/hardware.h> | 10 | #include <asm/arch/hardware.h> |
10 | #include <asm/mach-types.h> | 11 | #include <asm/arch/prcm.h> |
12 | |||
13 | #ifndef CONFIG_MACH_VOICEBLUE | ||
14 | #define voiceblue_reset() do {} while (0) | ||
15 | #endif | ||
11 | 16 | ||
12 | static inline void arch_idle(void) | 17 | static inline void arch_idle(void) |
13 | { | 18 | { |
14 | cpu_do_idle(); | 19 | cpu_do_idle(); |
15 | } | 20 | } |
16 | 21 | ||
17 | static inline void arch_reset(char mode) | 22 | static inline void omap1_arch_reset(char mode) |
18 | { | 23 | { |
19 | |||
20 | #ifdef CONFIG_ARCH_OMAP16XX | ||
21 | /* | 24 | /* |
22 | * Workaround for 5912/1611b bug mentioned in sprz209d.pdf p. 28 | 25 | * Workaround for 5912/1611b bug mentioned in sprz209d.pdf p. 28 |
23 | * "Global Software Reset Affects Traffic Controller Frequency". | 26 | * "Global Software Reset Affects Traffic Controller Frequency". |
@@ -27,13 +30,31 @@ static inline void arch_reset(char mode) | |||
27 | DPLL_CTL); | 30 | DPLL_CTL); |
28 | omap_writew(0x8, ARM_RSTCT1); | 31 | omap_writew(0x8, ARM_RSTCT1); |
29 | } | 32 | } |
30 | #endif | 33 | |
31 | #ifdef CONFIG_MACH_VOICEBLUE | ||
32 | if (machine_is_voiceblue()) | 34 | if (machine_is_voiceblue()) |
33 | voiceblue_reset(); | 35 | voiceblue_reset(); |
34 | else | 36 | else |
35 | #endif | ||
36 | omap_writew(1, ARM_RSTCT1); | 37 | omap_writew(1, ARM_RSTCT1); |
37 | } | 38 | } |
38 | 39 | ||
40 | static inline void omap2_arch_reset(char mode) | ||
41 | { | ||
42 | u32 rate; | ||
43 | struct clk *vclk, *sclk; | ||
44 | |||
45 | vclk = clk_get(NULL, "virt_prcm_set"); | ||
46 | sclk = clk_get(NULL, "sys_ck"); | ||
47 | rate = clk_get_rate(sclk); | ||
48 | clk_set_rate(vclk, rate); /* go to bypass for OMAP limitation */ | ||
49 | RM_RSTCTRL_WKUP |= 2; | ||
50 | } | ||
51 | |||
52 | static inline void arch_reset(char mode) | ||
53 | { | ||
54 | if (!cpu_is_omap24xx()) | ||
55 | omap1_arch_reset(mode); | ||
56 | else | ||
57 | omap2_arch_reset(mode); | ||
58 | } | ||
59 | |||
39 | #endif | 60 | #endif |
diff --git a/include/asm-arm/arch-omap/timex.h b/include/asm-arm/arch-omap/timex.h index b61ddb491e83..21f2e367185a 100644 --- a/include/asm-arm/arch-omap/timex.h +++ b/include/asm-arm/arch-omap/timex.h | |||
@@ -28,6 +28,14 @@ | |||
28 | #if !defined(__ASM_ARCH_OMAP_TIMEX_H) | 28 | #if !defined(__ASM_ARCH_OMAP_TIMEX_H) |
29 | #define __ASM_ARCH_OMAP_TIMEX_H | 29 | #define __ASM_ARCH_OMAP_TIMEX_H |
30 | 30 | ||
31 | /* | ||
32 | * OMAP 32KHz timer updates time one jiffie at a time from a secondary timer, | ||
33 | * and that's why the CLOCK_TICK_RATE is not 32768. | ||
34 | */ | ||
35 | #ifdef CONFIG_OMAP_32K_TIMER | ||
36 | #define CLOCK_TICK_RATE (CONFIG_OMAP_32K_TIMER_HZ) | ||
37 | #else | ||
31 | #define CLOCK_TICK_RATE (HZ * 100000UL) | 38 | #define CLOCK_TICK_RATE (HZ * 100000UL) |
39 | #endif | ||
32 | 40 | ||
33 | #endif /* __ASM_ARCH_OMAP_TIMEX_H */ | 41 | #endif /* __ASM_ARCH_OMAP_TIMEX_H */ |
diff --git a/include/asm-arm/arch-omap/uncompress.h b/include/asm-arm/arch-omap/uncompress.h index 3545c86859cc..c718264affbd 100644 --- a/include/asm-arm/arch-omap/uncompress.h +++ b/include/asm-arm/arch-omap/uncompress.h | |||
@@ -36,10 +36,14 @@ putstr(const char *s) | |||
36 | volatile u8 * uart = 0; | 36 | volatile u8 * uart = 0; |
37 | int shift = 2; | 37 | int shift = 2; |
38 | 38 | ||
39 | #ifdef CONFIG_MACH_OMAP_PALMTE | ||
40 | return; | ||
41 | #endif | ||
42 | |||
39 | #ifdef CONFIG_ARCH_OMAP | 43 | #ifdef CONFIG_ARCH_OMAP |
40 | #ifdef CONFIG_OMAP_LL_DEBUG_UART3 | 44 | #ifdef CONFIG_OMAP_LL_DEBUG_UART3 |
41 | uart = (volatile u8 *)(OMAP_UART3_BASE); | 45 | uart = (volatile u8 *)(OMAP_UART3_BASE); |
42 | #elif CONFIG_OMAP_LL_DEBUG_UART2 | 46 | #elif defined(CONFIG_OMAP_LL_DEBUG_UART2) |
43 | uart = (volatile u8 *)(OMAP_UART2_BASE); | 47 | uart = (volatile u8 *)(OMAP_UART2_BASE); |
44 | #else | 48 | #else |
45 | uart = (volatile u8 *)(OMAP_UART1_BASE); | 49 | uart = (volatile u8 *)(OMAP_UART1_BASE); |
diff --git a/include/asm-arm/arch-pxa/sharpsl.h b/include/asm-arm/arch-pxa/sharpsl.h index 311f2bb5386a..0b43495d24b4 100644 --- a/include/asm-arm/arch-pxa/sharpsl.h +++ b/include/asm-arm/arch-pxa/sharpsl.h | |||
@@ -21,12 +21,18 @@ struct corgits_machinfo { | |||
21 | void (*wait_hsync)(void); | 21 | void (*wait_hsync)(void); |
22 | }; | 22 | }; |
23 | 23 | ||
24 | |||
24 | /* | 25 | /* |
25 | * SharpSL Backlight | 26 | * SharpSL Backlight |
26 | */ | 27 | */ |
27 | |||
28 | struct corgibl_machinfo { | 28 | struct corgibl_machinfo { |
29 | int max_intensity; | 29 | int max_intensity; |
30 | void (*set_bl_intensity)(int intensity); | 30 | void (*set_bl_intensity)(int intensity); |
31 | }; | 31 | }; |
32 | extern void corgibl_limit_intensity(int limit); | ||
33 | |||
32 | 34 | ||
35 | /* | ||
36 | * SharpSL Battery/PM Driver | ||
37 | */ | ||
38 | extern void sharpsl_battery_kick(void); | ||
diff --git a/include/asm-arm/arch-pxa/ssp.h b/include/asm-arm/arch-pxa/ssp.h index 6ec67b018c09..949878c0d908 100644 --- a/include/asm-arm/arch-pxa/ssp.h +++ b/include/asm-arm/arch-pxa/ssp.h | |||
@@ -18,6 +18,11 @@ | |||
18 | #ifndef SSP_H | 18 | #ifndef SSP_H |
19 | #define SSP_H | 19 | #define SSP_H |
20 | 20 | ||
21 | /* | ||
22 | * SSP initialisation flags | ||
23 | */ | ||
24 | #define SSP_NO_IRQ 0x1 /* don't register an irq handler in SSP driver */ | ||
25 | |||
21 | struct ssp_state { | 26 | struct ssp_state { |
22 | u32 cr0; | 27 | u32 cr0; |
23 | u32 cr1; | 28 | u32 cr1; |
@@ -31,6 +36,7 @@ struct ssp_dev { | |||
31 | u32 flags; | 36 | u32 flags; |
32 | u32 psp_flags; | 37 | u32 psp_flags; |
33 | u32 speed; | 38 | u32 speed; |
39 | int irq; | ||
34 | }; | 40 | }; |
35 | 41 | ||
36 | int ssp_write_word(struct ssp_dev *dev, u32 data); | 42 | int ssp_write_word(struct ssp_dev *dev, u32 data); |
@@ -40,7 +46,7 @@ void ssp_enable(struct ssp_dev *dev); | |||
40 | void ssp_disable(struct ssp_dev *dev); | 46 | void ssp_disable(struct ssp_dev *dev); |
41 | void ssp_save_state(struct ssp_dev *dev, struct ssp_state *ssp); | 47 | void ssp_save_state(struct ssp_dev *dev, struct ssp_state *ssp); |
42 | void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *ssp); | 48 | void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *ssp); |
43 | int ssp_init(struct ssp_dev *dev, u32 port); | 49 | int ssp_init(struct ssp_dev *dev, u32 port, u32 init_flags); |
44 | int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32 psp_flags, u32 speed); | 50 | int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32 psp_flags, u32 speed); |
45 | void ssp_exit(struct ssp_dev *dev); | 51 | void ssp_exit(struct ssp_dev *dev); |
46 | 52 | ||
diff --git a/include/asm-i386/ide.h b/include/asm-i386/ide.h index 79dfab87135d..454440193eac 100644 --- a/include/asm-i386/ide.h +++ b/include/asm-i386/ide.h | |||
@@ -41,6 +41,12 @@ static __inline__ int ide_default_irq(unsigned long base) | |||
41 | 41 | ||
42 | static __inline__ unsigned long ide_default_io_base(int index) | 42 | static __inline__ unsigned long ide_default_io_base(int index) |
43 | { | 43 | { |
44 | /* | ||
45 | * If PCI is present then it is not safe to poke around | ||
46 | * the other legacy IDE ports. Only 0x1f0 and 0x170 are | ||
47 | * defined compatibility mode ports for PCI. A user can | ||
48 | * override this using ide= but we must default safe. | ||
49 | */ | ||
44 | if (pci_find_device(PCI_ANY_ID, PCI_ANY_ID, NULL) == NULL) { | 50 | if (pci_find_device(PCI_ANY_ID, PCI_ANY_ID, NULL) == NULL) { |
45 | switch(index) { | 51 | switch(index) { |
46 | case 2: return 0x1e8; | 52 | case 2: return 0x1e8; |
diff --git a/include/asm-ppc64/abs_addr.h b/include/asm-powerpc/abs_addr.h index dc3fc3fefef2..18415108fc56 100644 --- a/include/asm-ppc64/abs_addr.h +++ b/include/asm-powerpc/abs_addr.h | |||
@@ -1,5 +1,5 @@ | |||
1 | #ifndef _ABS_ADDR_H | 1 | #ifndef _ASM_POWERPC_ABS_ADDR_H |
2 | #define _ABS_ADDR_H | 2 | #define _ASM_POWERPC_ABS_ADDR_H |
3 | 3 | ||
4 | #include <linux/config.h> | 4 | #include <linux/config.h> |
5 | 5 | ||
@@ -70,4 +70,4 @@ static inline unsigned long phys_to_abs(unsigned long pa) | |||
70 | #define iseries_hv_addr(virtaddr) \ | 70 | #define iseries_hv_addr(virtaddr) \ |
71 | (0x8000000000000000 | virt_to_abs(virtaddr)) | 71 | (0x8000000000000000 | virt_to_abs(virtaddr)) |
72 | 72 | ||
73 | #endif /* _ABS_ADDR_H */ | 73 | #endif /* _ASM_POWERPC_ABS_ADDR_H */ |
diff --git a/include/asm-powerpc/asm-compat.h b/include/asm-powerpc/asm-compat.h new file mode 100644 index 000000000000..8b133efc9f79 --- /dev/null +++ b/include/asm-powerpc/asm-compat.h | |||
@@ -0,0 +1,55 @@ | |||
1 | #ifndef _ASM_POWERPC_ASM_COMPAT_H | ||
2 | #define _ASM_POWERPC_ASM_COMPAT_H | ||
3 | |||
4 | #include <linux/config.h> | ||
5 | #include <asm/types.h> | ||
6 | |||
7 | #ifdef __ASSEMBLY__ | ||
8 | # define stringify_in_c(...) __VA_ARGS__ | ||
9 | # define ASM_CONST(x) x | ||
10 | #else | ||
11 | /* This version of stringify will deal with commas... */ | ||
12 | # define __stringify_in_c(...) #__VA_ARGS__ | ||
13 | # define stringify_in_c(...) __stringify_in_c(__VA_ARGS__) " " | ||
14 | # define __ASM_CONST(x) x##UL | ||
15 | # define ASM_CONST(x) __ASM_CONST(x) | ||
16 | #endif | ||
17 | |||
18 | #ifdef __powerpc64__ | ||
19 | |||
20 | /* operations for longs and pointers */ | ||
21 | #define PPC_LL stringify_in_c(ld) | ||
22 | #define PPC_STL stringify_in_c(std) | ||
23 | #define PPC_LCMPI stringify_in_c(cmpdi) | ||
24 | #define PPC_LONG stringify_in_c(.llong) | ||
25 | #define PPC_TLNEI stringify_in_c(tdnei) | ||
26 | #define PPC_LLARX stringify_in_c(ldarx) | ||
27 | #define PPC_STLCX stringify_in_c(stdcx.) | ||
28 | #define PPC_CNTLZL stringify_in_c(cntlzd) | ||
29 | |||
30 | #else /* 32-bit */ | ||
31 | |||
32 | /* operations for longs and pointers */ | ||
33 | #define PPC_LL stringify_in_c(lwz) | ||
34 | #define PPC_STL stringify_in_c(stw) | ||
35 | #define PPC_LCMPI stringify_in_c(cmpwi) | ||
36 | #define PPC_LONG stringify_in_c(.long) | ||
37 | #define PPC_TLNEI stringify_in_c(twnei) | ||
38 | #define PPC_LLARX stringify_in_c(lwarx) | ||
39 | #define PPC_STLCX stringify_in_c(stwcx.) | ||
40 | #define PPC_CNTLZL stringify_in_c(cntlzw) | ||
41 | |||
42 | #endif | ||
43 | |||
44 | #ifdef CONFIG_IBM405_ERR77 | ||
45 | /* Erratum #77 on the 405 means we need a sync or dcbt before every | ||
46 | * stwcx. The old ATOMIC_SYNC_FIX covered some but not all of this. | ||
47 | */ | ||
48 | #define PPC405_ERR77(ra,rb) stringify_in_c(dcbt ra, rb;) | ||
49 | #define PPC405_ERR77_SYNC stringify_in_c(sync;) | ||
50 | #else | ||
51 | #define PPC405_ERR77(ra,rb) | ||
52 | #define PPC405_ERR77_SYNC | ||
53 | #endif | ||
54 | |||
55 | #endif /* _ASM_POWERPC_ASM_COMPAT_H */ | ||
diff --git a/include/asm-powerpc/atomic.h b/include/asm-powerpc/atomic.h index ed4b345ed75d..9c0b372a46e1 100644 --- a/include/asm-powerpc/atomic.h +++ b/include/asm-powerpc/atomic.h | |||
@@ -9,21 +9,13 @@ typedef struct { volatile int counter; } atomic_t; | |||
9 | 9 | ||
10 | #ifdef __KERNEL__ | 10 | #ifdef __KERNEL__ |
11 | #include <asm/synch.h> | 11 | #include <asm/synch.h> |
12 | #include <asm/asm-compat.h> | ||
12 | 13 | ||
13 | #define ATOMIC_INIT(i) { (i) } | 14 | #define ATOMIC_INIT(i) { (i) } |
14 | 15 | ||
15 | #define atomic_read(v) ((v)->counter) | 16 | #define atomic_read(v) ((v)->counter) |
16 | #define atomic_set(v,i) (((v)->counter) = (i)) | 17 | #define atomic_set(v,i) (((v)->counter) = (i)) |
17 | 18 | ||
18 | /* Erratum #77 on the 405 means we need a sync or dcbt before every stwcx. | ||
19 | * The old ATOMIC_SYNC_FIX covered some but not all of this. | ||
20 | */ | ||
21 | #ifdef CONFIG_IBM405_ERR77 | ||
22 | #define PPC405_ERR77(ra,rb) "dcbt " #ra "," #rb ";" | ||
23 | #else | ||
24 | #define PPC405_ERR77(ra,rb) | ||
25 | #endif | ||
26 | |||
27 | static __inline__ void atomic_add(int a, atomic_t *v) | 19 | static __inline__ void atomic_add(int a, atomic_t *v) |
28 | { | 20 | { |
29 | int t; | 21 | int t; |
@@ -205,5 +197,183 @@ static __inline__ int atomic_dec_if_positive(atomic_t *v) | |||
205 | #define smp_mb__before_atomic_inc() smp_mb() | 197 | #define smp_mb__before_atomic_inc() smp_mb() |
206 | #define smp_mb__after_atomic_inc() smp_mb() | 198 | #define smp_mb__after_atomic_inc() smp_mb() |
207 | 199 | ||
200 | #ifdef __powerpc64__ | ||
201 | |||
202 | typedef struct { volatile long counter; } atomic64_t; | ||
203 | |||
204 | #define ATOMIC64_INIT(i) { (i) } | ||
205 | |||
206 | #define atomic64_read(v) ((v)->counter) | ||
207 | #define atomic64_set(v,i) (((v)->counter) = (i)) | ||
208 | |||
209 | static __inline__ void atomic64_add(long a, atomic64_t *v) | ||
210 | { | ||
211 | long t; | ||
212 | |||
213 | __asm__ __volatile__( | ||
214 | "1: ldarx %0,0,%3 # atomic64_add\n\ | ||
215 | add %0,%2,%0\n\ | ||
216 | stdcx. %0,0,%3 \n\ | ||
217 | bne- 1b" | ||
218 | : "=&r" (t), "=m" (v->counter) | ||
219 | : "r" (a), "r" (&v->counter), "m" (v->counter) | ||
220 | : "cc"); | ||
221 | } | ||
222 | |||
223 | static __inline__ long atomic64_add_return(long a, atomic64_t *v) | ||
224 | { | ||
225 | long t; | ||
226 | |||
227 | __asm__ __volatile__( | ||
228 | EIEIO_ON_SMP | ||
229 | "1: ldarx %0,0,%2 # atomic64_add_return\n\ | ||
230 | add %0,%1,%0\n\ | ||
231 | stdcx. %0,0,%2 \n\ | ||
232 | bne- 1b" | ||
233 | ISYNC_ON_SMP | ||
234 | : "=&r" (t) | ||
235 | : "r" (a), "r" (&v->counter) | ||
236 | : "cc", "memory"); | ||
237 | |||
238 | return t; | ||
239 | } | ||
240 | |||
241 | #define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) | ||
242 | |||
243 | static __inline__ void atomic64_sub(long a, atomic64_t *v) | ||
244 | { | ||
245 | long t; | ||
246 | |||
247 | __asm__ __volatile__( | ||
248 | "1: ldarx %0,0,%3 # atomic64_sub\n\ | ||
249 | subf %0,%2,%0\n\ | ||
250 | stdcx. %0,0,%3 \n\ | ||
251 | bne- 1b" | ||
252 | : "=&r" (t), "=m" (v->counter) | ||
253 | : "r" (a), "r" (&v->counter), "m" (v->counter) | ||
254 | : "cc"); | ||
255 | } | ||
256 | |||
257 | static __inline__ long atomic64_sub_return(long a, atomic64_t *v) | ||
258 | { | ||
259 | long t; | ||
260 | |||
261 | __asm__ __volatile__( | ||
262 | EIEIO_ON_SMP | ||
263 | "1: ldarx %0,0,%2 # atomic64_sub_return\n\ | ||
264 | subf %0,%1,%0\n\ | ||
265 | stdcx. %0,0,%2 \n\ | ||
266 | bne- 1b" | ||
267 | ISYNC_ON_SMP | ||
268 | : "=&r" (t) | ||
269 | : "r" (a), "r" (&v->counter) | ||
270 | : "cc", "memory"); | ||
271 | |||
272 | return t; | ||
273 | } | ||
274 | |||
275 | static __inline__ void atomic64_inc(atomic64_t *v) | ||
276 | { | ||
277 | long t; | ||
278 | |||
279 | __asm__ __volatile__( | ||
280 | "1: ldarx %0,0,%2 # atomic64_inc\n\ | ||
281 | addic %0,%0,1\n\ | ||
282 | stdcx. %0,0,%2 \n\ | ||
283 | bne- 1b" | ||
284 | : "=&r" (t), "=m" (v->counter) | ||
285 | : "r" (&v->counter), "m" (v->counter) | ||
286 | : "cc"); | ||
287 | } | ||
288 | |||
289 | static __inline__ long atomic64_inc_return(atomic64_t *v) | ||
290 | { | ||
291 | long t; | ||
292 | |||
293 | __asm__ __volatile__( | ||
294 | EIEIO_ON_SMP | ||
295 | "1: ldarx %0,0,%1 # atomic64_inc_return\n\ | ||
296 | addic %0,%0,1\n\ | ||
297 | stdcx. %0,0,%1 \n\ | ||
298 | bne- 1b" | ||
299 | ISYNC_ON_SMP | ||
300 | : "=&r" (t) | ||
301 | : "r" (&v->counter) | ||
302 | : "cc", "memory"); | ||
303 | |||
304 | return t; | ||
305 | } | ||
306 | |||
307 | /* | ||
308 | * atomic64_inc_and_test - increment and test | ||
309 | * @v: pointer of type atomic64_t | ||
310 | * | ||
311 | * Atomically increments @v by 1 | ||
312 | * and returns true if the result is zero, or false for all | ||
313 | * other cases. | ||
314 | */ | ||
315 | #define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) | ||
316 | |||
317 | static __inline__ void atomic64_dec(atomic64_t *v) | ||
318 | { | ||
319 | long t; | ||
320 | |||
321 | __asm__ __volatile__( | ||
322 | "1: ldarx %0,0,%2 # atomic64_dec\n\ | ||
323 | addic %0,%0,-1\n\ | ||
324 | stdcx. %0,0,%2\n\ | ||
325 | bne- 1b" | ||
326 | : "=&r" (t), "=m" (v->counter) | ||
327 | : "r" (&v->counter), "m" (v->counter) | ||
328 | : "cc"); | ||
329 | } | ||
330 | |||
331 | static __inline__ long atomic64_dec_return(atomic64_t *v) | ||
332 | { | ||
333 | long t; | ||
334 | |||
335 | __asm__ __volatile__( | ||
336 | EIEIO_ON_SMP | ||
337 | "1: ldarx %0,0,%1 # atomic64_dec_return\n\ | ||
338 | addic %0,%0,-1\n\ | ||
339 | stdcx. %0,0,%1\n\ | ||
340 | bne- 1b" | ||
341 | ISYNC_ON_SMP | ||
342 | : "=&r" (t) | ||
343 | : "r" (&v->counter) | ||
344 | : "cc", "memory"); | ||
345 | |||
346 | return t; | ||
347 | } | ||
348 | |||
349 | #define atomic64_sub_and_test(a, v) (atomic64_sub_return((a), (v)) == 0) | ||
350 | #define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0) | ||
351 | |||
352 | /* | ||
353 | * Atomically test *v and decrement if it is greater than 0. | ||
354 | * The function returns the old value of *v minus 1. | ||
355 | */ | ||
356 | static __inline__ long atomic64_dec_if_positive(atomic64_t *v) | ||
357 | { | ||
358 | long t; | ||
359 | |||
360 | __asm__ __volatile__( | ||
361 | EIEIO_ON_SMP | ||
362 | "1: ldarx %0,0,%1 # atomic64_dec_if_positive\n\ | ||
363 | addic. %0,%0,-1\n\ | ||
364 | blt- 2f\n\ | ||
365 | stdcx. %0,0,%1\n\ | ||
366 | bne- 1b" | ||
367 | ISYNC_ON_SMP | ||
368 | "\n\ | ||
369 | 2:" : "=&r" (t) | ||
370 | : "r" (&v->counter) | ||
371 | : "cc", "memory"); | ||
372 | |||
373 | return t; | ||
374 | } | ||
375 | |||
376 | #endif /* __powerpc64__ */ | ||
377 | |||
208 | #endif /* __KERNEL__ */ | 378 | #endif /* __KERNEL__ */ |
209 | #endif /* _ASM_POWERPC_ATOMIC_H_ */ | 379 | #endif /* _ASM_POWERPC_ATOMIC_H_ */ |
diff --git a/include/asm-powerpc/bitops.h b/include/asm-powerpc/bitops.h index dc25c53704d5..5727229b0444 100644 --- a/include/asm-powerpc/bitops.h +++ b/include/asm-powerpc/bitops.h | |||
@@ -40,6 +40,7 @@ | |||
40 | 40 | ||
41 | #include <linux/compiler.h> | 41 | #include <linux/compiler.h> |
42 | #include <asm/atomic.h> | 42 | #include <asm/atomic.h> |
43 | #include <asm/asm-compat.h> | ||
43 | #include <asm/synch.h> | 44 | #include <asm/synch.h> |
44 | 45 | ||
45 | /* | 46 | /* |
@@ -52,16 +53,6 @@ | |||
52 | #define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) | 53 | #define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) |
53 | #define BITOP_LE_SWIZZLE ((BITS_PER_LONG-1) & ~0x7) | 54 | #define BITOP_LE_SWIZZLE ((BITS_PER_LONG-1) & ~0x7) |
54 | 55 | ||
55 | #ifdef CONFIG_PPC64 | ||
56 | #define LARXL "ldarx" | ||
57 | #define STCXL "stdcx." | ||
58 | #define CNTLZL "cntlzd" | ||
59 | #else | ||
60 | #define LARXL "lwarx" | ||
61 | #define STCXL "stwcx." | ||
62 | #define CNTLZL "cntlzw" | ||
63 | #endif | ||
64 | |||
65 | static __inline__ void set_bit(int nr, volatile unsigned long *addr) | 56 | static __inline__ void set_bit(int nr, volatile unsigned long *addr) |
66 | { | 57 | { |
67 | unsigned long old; | 58 | unsigned long old; |
@@ -69,10 +60,10 @@ static __inline__ void set_bit(int nr, volatile unsigned long *addr) | |||
69 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 60 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); |
70 | 61 | ||
71 | __asm__ __volatile__( | 62 | __asm__ __volatile__( |
72 | "1:" LARXL " %0,0,%3 # set_bit\n" | 63 | "1:" PPC_LLARX "%0,0,%3 # set_bit\n" |
73 | "or %0,%0,%2\n" | 64 | "or %0,%0,%2\n" |
74 | PPC405_ERR77(0,%3) | 65 | PPC405_ERR77(0,%3) |
75 | STCXL " %0,0,%3\n" | 66 | PPC_STLCX "%0,0,%3\n" |
76 | "bne- 1b" | 67 | "bne- 1b" |
77 | : "=&r"(old), "=m"(*p) | 68 | : "=&r"(old), "=m"(*p) |
78 | : "r"(mask), "r"(p), "m"(*p) | 69 | : "r"(mask), "r"(p), "m"(*p) |
@@ -86,10 +77,10 @@ static __inline__ void clear_bit(int nr, volatile unsigned long *addr) | |||
86 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 77 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); |
87 | 78 | ||
88 | __asm__ __volatile__( | 79 | __asm__ __volatile__( |
89 | "1:" LARXL " %0,0,%3 # set_bit\n" | 80 | "1:" PPC_LLARX "%0,0,%3 # clear_bit\n" |
90 | "andc %0,%0,%2\n" | 81 | "andc %0,%0,%2\n" |
91 | PPC405_ERR77(0,%3) | 82 | PPC405_ERR77(0,%3) |
92 | STCXL " %0,0,%3\n" | 83 | PPC_STLCX "%0,0,%3\n" |
93 | "bne- 1b" | 84 | "bne- 1b" |
94 | : "=&r"(old), "=m"(*p) | 85 | : "=&r"(old), "=m"(*p) |
95 | : "r"(mask), "r"(p), "m"(*p) | 86 | : "r"(mask), "r"(p), "m"(*p) |
@@ -103,10 +94,10 @@ static __inline__ void change_bit(int nr, volatile unsigned long *addr) | |||
103 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 94 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); |
104 | 95 | ||
105 | __asm__ __volatile__( | 96 | __asm__ __volatile__( |
106 | "1:" LARXL " %0,0,%3 # set_bit\n" | 97 | "1:" PPC_LLARX "%0,0,%3 # change_bit\n" |
107 | "xor %0,%0,%2\n" | 98 | "xor %0,%0,%2\n" |
108 | PPC405_ERR77(0,%3) | 99 | PPC405_ERR77(0,%3) |
109 | STCXL " %0,0,%3\n" | 100 | PPC_STLCX "%0,0,%3\n" |
110 | "bne- 1b" | 101 | "bne- 1b" |
111 | : "=&r"(old), "=m"(*p) | 102 | : "=&r"(old), "=m"(*p) |
112 | : "r"(mask), "r"(p), "m"(*p) | 103 | : "r"(mask), "r"(p), "m"(*p) |
@@ -122,10 +113,10 @@ static __inline__ int test_and_set_bit(unsigned long nr, | |||
122 | 113 | ||
123 | __asm__ __volatile__( | 114 | __asm__ __volatile__( |
124 | EIEIO_ON_SMP | 115 | EIEIO_ON_SMP |
125 | "1:" LARXL " %0,0,%3 # test_and_set_bit\n" | 116 | "1:" PPC_LLARX "%0,0,%3 # test_and_set_bit\n" |
126 | "or %1,%0,%2 \n" | 117 | "or %1,%0,%2 \n" |
127 | PPC405_ERR77(0,%3) | 118 | PPC405_ERR77(0,%3) |
128 | STCXL " %1,0,%3 \n" | 119 | PPC_STLCX "%1,0,%3 \n" |
129 | "bne- 1b" | 120 | "bne- 1b" |
130 | ISYNC_ON_SMP | 121 | ISYNC_ON_SMP |
131 | : "=&r" (old), "=&r" (t) | 122 | : "=&r" (old), "=&r" (t) |
@@ -144,10 +135,10 @@ static __inline__ int test_and_clear_bit(unsigned long nr, | |||
144 | 135 | ||
145 | __asm__ __volatile__( | 136 | __asm__ __volatile__( |
146 | EIEIO_ON_SMP | 137 | EIEIO_ON_SMP |
147 | "1:" LARXL " %0,0,%3 # test_and_clear_bit\n" | 138 | "1:" PPC_LLARX "%0,0,%3 # test_and_clear_bit\n" |
148 | "andc %1,%0,%2 \n" | 139 | "andc %1,%0,%2 \n" |
149 | PPC405_ERR77(0,%3) | 140 | PPC405_ERR77(0,%3) |
150 | STCXL " %1,0,%3 \n" | 141 | PPC_STLCX "%1,0,%3 \n" |
151 | "bne- 1b" | 142 | "bne- 1b" |
152 | ISYNC_ON_SMP | 143 | ISYNC_ON_SMP |
153 | : "=&r" (old), "=&r" (t) | 144 | : "=&r" (old), "=&r" (t) |
@@ -166,10 +157,10 @@ static __inline__ int test_and_change_bit(unsigned long nr, | |||
166 | 157 | ||
167 | __asm__ __volatile__( | 158 | __asm__ __volatile__( |
168 | EIEIO_ON_SMP | 159 | EIEIO_ON_SMP |
169 | "1:" LARXL " %0,0,%3 # test_and_change_bit\n" | 160 | "1:" PPC_LLARX "%0,0,%3 # test_and_change_bit\n" |
170 | "xor %1,%0,%2 \n" | 161 | "xor %1,%0,%2 \n" |
171 | PPC405_ERR77(0,%3) | 162 | PPC405_ERR77(0,%3) |
172 | STCXL " %1,0,%3 \n" | 163 | PPC_STLCX "%1,0,%3 \n" |
173 | "bne- 1b" | 164 | "bne- 1b" |
174 | ISYNC_ON_SMP | 165 | ISYNC_ON_SMP |
175 | : "=&r" (old), "=&r" (t) | 166 | : "=&r" (old), "=&r" (t) |
@@ -184,9 +175,9 @@ static __inline__ void set_bits(unsigned long mask, unsigned long *addr) | |||
184 | unsigned long old; | 175 | unsigned long old; |
185 | 176 | ||
186 | __asm__ __volatile__( | 177 | __asm__ __volatile__( |
187 | "1:" LARXL " %0,0,%3 # set_bit\n" | 178 | "1:" PPC_LLARX "%0,0,%3 # set_bits\n" |
188 | "or %0,%0,%2\n" | 179 | "or %0,%0,%2\n" |
189 | STCXL " %0,0,%3\n" | 180 | PPC_STLCX "%0,0,%3\n" |
190 | "bne- 1b" | 181 | "bne- 1b" |
191 | : "=&r" (old), "=m" (*addr) | 182 | : "=&r" (old), "=m" (*addr) |
192 | : "r" (mask), "r" (addr), "m" (*addr) | 183 | : "r" (mask), "r" (addr), "m" (*addr) |
@@ -268,7 +259,7 @@ static __inline__ int __ilog2(unsigned long x) | |||
268 | { | 259 | { |
269 | int lz; | 260 | int lz; |
270 | 261 | ||
271 | asm (CNTLZL " %0,%1" : "=r" (lz) : "r" (x)); | 262 | asm (PPC_CNTLZL "%0,%1" : "=r" (lz) : "r" (x)); |
272 | return BITS_PER_LONG - 1 - lz; | 263 | return BITS_PER_LONG - 1 - lz; |
273 | } | 264 | } |
274 | 265 | ||
diff --git a/include/asm-powerpc/bug.h b/include/asm-powerpc/bug.h index d625ee55f957..b001ecb3cd99 100644 --- a/include/asm-powerpc/bug.h +++ b/include/asm-powerpc/bug.h | |||
@@ -1,6 +1,7 @@ | |||
1 | #ifndef _ASM_POWERPC_BUG_H | 1 | #ifndef _ASM_POWERPC_BUG_H |
2 | #define _ASM_POWERPC_BUG_H | 2 | #define _ASM_POWERPC_BUG_H |
3 | 3 | ||
4 | #include <asm/asm-compat.h> | ||
4 | /* | 5 | /* |
5 | * Define an illegal instr to trap on the bug. | 6 | * Define an illegal instr to trap on the bug. |
6 | * We don't use 0 because that marks the end of a function | 7 | * We don't use 0 because that marks the end of a function |
@@ -11,14 +12,6 @@ | |||
11 | 12 | ||
12 | #ifndef __ASSEMBLY__ | 13 | #ifndef __ASSEMBLY__ |
13 | 14 | ||
14 | #ifdef __powerpc64__ | ||
15 | #define BUG_TABLE_ENTRY ".llong" | ||
16 | #define BUG_TRAP_OP "tdnei" | ||
17 | #else | ||
18 | #define BUG_TABLE_ENTRY ".long" | ||
19 | #define BUG_TRAP_OP "twnei" | ||
20 | #endif /* __powerpc64__ */ | ||
21 | |||
22 | struct bug_entry { | 15 | struct bug_entry { |
23 | unsigned long bug_addr; | 16 | unsigned long bug_addr; |
24 | long line; | 17 | long line; |
@@ -40,16 +33,16 @@ struct bug_entry *find_bug(unsigned long bugaddr); | |||
40 | __asm__ __volatile__( \ | 33 | __asm__ __volatile__( \ |
41 | "1: twi 31,0,0\n" \ | 34 | "1: twi 31,0,0\n" \ |
42 | ".section __bug_table,\"a\"\n" \ | 35 | ".section __bug_table,\"a\"\n" \ |
43 | "\t"BUG_TABLE_ENTRY" 1b,%0,%1,%2\n" \ | 36 | "\t"PPC_LONG" 1b,%0,%1,%2\n" \ |
44 | ".previous" \ | 37 | ".previous" \ |
45 | : : "i" (__LINE__), "i" (__FILE__), "i" (__FUNCTION__)); \ | 38 | : : "i" (__LINE__), "i" (__FILE__), "i" (__FUNCTION__)); \ |
46 | } while (0) | 39 | } while (0) |
47 | 40 | ||
48 | #define BUG_ON(x) do { \ | 41 | #define BUG_ON(x) do { \ |
49 | __asm__ __volatile__( \ | 42 | __asm__ __volatile__( \ |
50 | "1: "BUG_TRAP_OP" %0,0\n" \ | 43 | "1: "PPC_TLNEI" %0,0\n" \ |
51 | ".section __bug_table,\"a\"\n" \ | 44 | ".section __bug_table,\"a\"\n" \ |
52 | "\t"BUG_TABLE_ENTRY" 1b,%1,%2,%3\n" \ | 45 | "\t"PPC_LONG" 1b,%1,%2,%3\n" \ |
53 | ".previous" \ | 46 | ".previous" \ |
54 | : : "r" ((long)(x)), "i" (__LINE__), \ | 47 | : : "r" ((long)(x)), "i" (__LINE__), \ |
55 | "i" (__FILE__), "i" (__FUNCTION__)); \ | 48 | "i" (__FILE__), "i" (__FUNCTION__)); \ |
@@ -57,9 +50,9 @@ struct bug_entry *find_bug(unsigned long bugaddr); | |||
57 | 50 | ||
58 | #define WARN_ON(x) do { \ | 51 | #define WARN_ON(x) do { \ |
59 | __asm__ __volatile__( \ | 52 | __asm__ __volatile__( \ |
60 | "1: "BUG_TRAP_OP" %0,0\n" \ | 53 | "1: "PPC_TLNEI" %0,0\n" \ |
61 | ".section __bug_table,\"a\"\n" \ | 54 | ".section __bug_table,\"a\"\n" \ |
62 | "\t"BUG_TABLE_ENTRY" 1b,%1,%2,%3\n" \ | 55 | "\t"PPC_LONG" 1b,%1,%2,%3\n" \ |
63 | ".previous" \ | 56 | ".previous" \ |
64 | : : "r" ((long)(x)), \ | 57 | : : "r" ((long)(x)), \ |
65 | "i" (__LINE__ + BUG_WARNING_TRAP), \ | 58 | "i" (__LINE__ + BUG_WARNING_TRAP), \ |
diff --git a/include/asm-powerpc/cache.h b/include/asm-powerpc/cache.h new file mode 100644 index 000000000000..26ce502e76e8 --- /dev/null +++ b/include/asm-powerpc/cache.h | |||
@@ -0,0 +1,40 @@ | |||
1 | #ifndef _ASM_POWERPC_CACHE_H | ||
2 | #define _ASM_POWERPC_CACHE_H | ||
3 | |||
4 | #ifdef __KERNEL__ | ||
5 | |||
6 | #include <linux/config.h> | ||
7 | |||
8 | /* bytes per L1 cache line */ | ||
9 | #if defined(CONFIG_8xx) || defined(CONFIG_403GCX) | ||
10 | #define L1_CACHE_SHIFT 4 | ||
11 | #define MAX_COPY_PREFETCH 1 | ||
12 | #elif defined(CONFIG_PPC32) | ||
13 | #define L1_CACHE_SHIFT 5 | ||
14 | #define MAX_COPY_PREFETCH 4 | ||
15 | #else /* CONFIG_PPC64 */ | ||
16 | #define L1_CACHE_SHIFT 7 | ||
17 | #endif | ||
18 | |||
19 | #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) | ||
20 | |||
21 | #define SMP_CACHE_BYTES L1_CACHE_BYTES | ||
22 | #define L1_CACHE_SHIFT_MAX 7 /* largest L1 which this arch supports */ | ||
23 | |||
24 | #if defined(__powerpc64__) && !defined(__ASSEMBLY__) | ||
25 | struct ppc64_caches { | ||
26 | u32 dsize; /* L1 d-cache size */ | ||
27 | u32 dline_size; /* L1 d-cache line size */ | ||
28 | u32 log_dline_size; | ||
29 | u32 dlines_per_page; | ||
30 | u32 isize; /* L1 i-cache size */ | ||
31 | u32 iline_size; /* L1 i-cache line size */ | ||
32 | u32 log_iline_size; | ||
33 | u32 ilines_per_page; | ||
34 | }; | ||
35 | |||
36 | extern struct ppc64_caches ppc64_caches; | ||
37 | #endif /* __powerpc64__ && ! __ASSEMBLY__ */ | ||
38 | |||
39 | #endif /* __KERNEL__ */ | ||
40 | #endif /* _ASM_POWERPC_CACHE_H */ | ||
diff --git a/include/asm-ppc64/cacheflush.h b/include/asm-powerpc/cacheflush.h index ffbc08be8e52..8a740c88d93d 100644 --- a/include/asm-ppc64/cacheflush.h +++ b/include/asm-powerpc/cacheflush.h | |||
@@ -1,13 +1,20 @@ | |||
1 | #ifndef _PPC64_CACHEFLUSH_H | 1 | /* |
2 | #define _PPC64_CACHEFLUSH_H | 2 | * This program is free software; you can redistribute it and/or |
3 | * modify it under the terms of the GNU General Public License | ||
4 | * as published by the Free Software Foundation; either version | ||
5 | * 2 of the License, or (at your option) any later version. | ||
6 | */ | ||
7 | #ifndef _ASM_POWERPC_CACHEFLUSH_H | ||
8 | #define _ASM_POWERPC_CACHEFLUSH_H | ||
9 | |||
10 | #ifdef __KERNEL__ | ||
3 | 11 | ||
4 | #include <linux/mm.h> | 12 | #include <linux/mm.h> |
5 | #include <asm/cputable.h> | 13 | #include <asm/cputable.h> |
6 | 14 | ||
7 | /* | 15 | /* |
8 | * No cache flushing is required when address mappings are | 16 | * No cache flushing is required when address mappings are changed, |
9 | * changed, because the caches on PowerPCs are physically | 17 | * because the caches on PowerPCs are physically addressed. |
10 | * addressed. | ||
11 | */ | 18 | */ |
12 | #define flush_cache_all() do { } while (0) | 19 | #define flush_cache_all() do { } while (0) |
13 | #define flush_cache_mm(mm) do { } while (0) | 20 | #define flush_cache_mm(mm) do { } while (0) |
@@ -22,27 +29,40 @@ extern void flush_dcache_page(struct page *page); | |||
22 | #define flush_dcache_mmap_unlock(mapping) do { } while (0) | 29 | #define flush_dcache_mmap_unlock(mapping) do { } while (0) |
23 | 30 | ||
24 | extern void __flush_icache_range(unsigned long, unsigned long); | 31 | extern void __flush_icache_range(unsigned long, unsigned long); |
32 | static inline void flush_icache_range(unsigned long start, unsigned long stop) | ||
33 | { | ||
34 | if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) | ||
35 | __flush_icache_range(start, stop); | ||
36 | } | ||
37 | |||
25 | extern void flush_icache_user_range(struct vm_area_struct *vma, | 38 | extern void flush_icache_user_range(struct vm_area_struct *vma, |
26 | struct page *page, unsigned long addr, | 39 | struct page *page, unsigned long addr, |
27 | int len); | 40 | int len); |
41 | extern void __flush_dcache_icache(void *page_va); | ||
42 | extern void flush_dcache_icache_page(struct page *page); | ||
43 | #if defined(CONFIG_PPC32) && !defined(CONFIG_BOOKE) | ||
44 | extern void __flush_dcache_icache_phys(unsigned long physaddr); | ||
45 | #endif /* CONFIG_PPC32 && !CONFIG_BOOKE */ | ||
28 | 46 | ||
29 | extern void flush_dcache_range(unsigned long start, unsigned long stop); | 47 | extern void flush_dcache_range(unsigned long start, unsigned long stop); |
30 | extern void flush_dcache_phys_range(unsigned long start, unsigned long stop); | 48 | #ifdef CONFIG_PPC32 |
49 | extern void clean_dcache_range(unsigned long start, unsigned long stop); | ||
50 | extern void invalidate_dcache_range(unsigned long start, unsigned long stop); | ||
51 | #endif /* CONFIG_PPC32 */ | ||
52 | #ifdef CONFIG_PPC64 | ||
31 | extern void flush_inval_dcache_range(unsigned long start, unsigned long stop); | 53 | extern void flush_inval_dcache_range(unsigned long start, unsigned long stop); |
54 | extern void flush_dcache_phys_range(unsigned long start, unsigned long stop); | ||
55 | #endif | ||
32 | 56 | ||
33 | #define copy_to_user_page(vma, page, vaddr, dst, src, len) \ | 57 | #define copy_to_user_page(vma, page, vaddr, dst, src, len) \ |
34 | do { memcpy(dst, src, len); \ | 58 | do { \ |
35 | flush_icache_user_range(vma, page, vaddr, len); \ | 59 | memcpy(dst, src, len); \ |
36 | } while (0) | 60 | flush_icache_user_range(vma, page, vaddr, len); \ |
61 | } while (0) | ||
37 | #define copy_from_user_page(vma, page, vaddr, dst, src, len) \ | 62 | #define copy_from_user_page(vma, page, vaddr, dst, src, len) \ |
38 | memcpy(dst, src, len) | 63 | memcpy(dst, src, len) |
39 | 64 | ||
40 | extern void __flush_dcache_icache(void *page_va); | ||
41 | 65 | ||
42 | static inline void flush_icache_range(unsigned long start, unsigned long stop) | 66 | #endif /* __KERNEL__ */ |
43 | { | ||
44 | if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) | ||
45 | __flush_icache_range(start, stop); | ||
46 | } | ||
47 | 67 | ||
48 | #endif /* _PPC64_CACHEFLUSH_H */ | 68 | #endif /* _ASM_POWERPC_CACHEFLUSH_H */ |
diff --git a/include/asm-ppc64/compat.h b/include/asm-powerpc/compat.h index 6ec62cd2d1d1..4db4360c4d4a 100644 --- a/include/asm-ppc64/compat.h +++ b/include/asm-powerpc/compat.h | |||
@@ -1,5 +1,5 @@ | |||
1 | #ifndef _ASM_PPC64_COMPAT_H | 1 | #ifndef _ASM_POWERPC_COMPAT_H |
2 | #define _ASM_PPC64_COMPAT_H | 2 | #define _ASM_POWERPC_COMPAT_H |
3 | /* | 3 | /* |
4 | * Architecture specific compatibility types | 4 | * Architecture specific compatibility types |
5 | */ | 5 | */ |
@@ -49,7 +49,7 @@ struct compat_stat { | |||
49 | compat_dev_t st_dev; | 49 | compat_dev_t st_dev; |
50 | compat_ino_t st_ino; | 50 | compat_ino_t st_ino; |
51 | compat_mode_t st_mode; | 51 | compat_mode_t st_mode; |
52 | compat_nlink_t st_nlink; | 52 | compat_nlink_t st_nlink; |
53 | __compat_uid32_t st_uid; | 53 | __compat_uid32_t st_uid; |
54 | __compat_gid32_t st_gid; | 54 | __compat_gid32_t st_gid; |
55 | compat_dev_t st_rdev; | 55 | compat_dev_t st_rdev; |
@@ -202,4 +202,4 @@ struct compat_shmid64_ds { | |||
202 | compat_ulong_t __unused6; | 202 | compat_ulong_t __unused6; |
203 | }; | 203 | }; |
204 | 204 | ||
205 | #endif /* _ASM_PPC64_COMPAT_H */ | 205 | #endif /* _ASM_POWERPC_COMPAT_H */ |
diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h index 79a0556a0ab8..04e2726002cf 100644 --- a/include/asm-powerpc/cputable.h +++ b/include/asm-powerpc/cputable.h | |||
@@ -2,7 +2,7 @@ | |||
2 | #define __ASM_POWERPC_CPUTABLE_H | 2 | #define __ASM_POWERPC_CPUTABLE_H |
3 | 3 | ||
4 | #include <linux/config.h> | 4 | #include <linux/config.h> |
5 | #include <asm/ppc_asm.h> /* for ASM_CONST */ | 5 | #include <asm/asm-compat.h> |
6 | 6 | ||
7 | #define PPC_FEATURE_32 0x80000000 | 7 | #define PPC_FEATURE_32 0x80000000 |
8 | #define PPC_FEATURE_64 0x40000000 | 8 | #define PPC_FEATURE_64 0x40000000 |
@@ -16,6 +16,10 @@ | |||
16 | #define PPC_FEATURE_HAS_EFP_SINGLE 0x00400000 | 16 | #define PPC_FEATURE_HAS_EFP_SINGLE 0x00400000 |
17 | #define PPC_FEATURE_HAS_EFP_DOUBLE 0x00200000 | 17 | #define PPC_FEATURE_HAS_EFP_DOUBLE 0x00200000 |
18 | #define PPC_FEATURE_NO_TB 0x00100000 | 18 | #define PPC_FEATURE_NO_TB 0x00100000 |
19 | #define PPC_FEATURE_POWER4 0x00080000 | ||
20 | #define PPC_FEATURE_POWER5 0x00040000 | ||
21 | #define PPC_FEATURE_POWER5_PLUS 0x00020000 | ||
22 | #define PPC_FEATURE_CELL 0x00010000 | ||
19 | 23 | ||
20 | #ifdef __KERNEL__ | 24 | #ifdef __KERNEL__ |
21 | #ifndef __ASSEMBLY__ | 25 | #ifndef __ASSEMBLY__ |
diff --git a/include/asm-powerpc/current.h b/include/asm-powerpc/current.h new file mode 100644 index 000000000000..82cd4a9ca99a --- /dev/null +++ b/include/asm-powerpc/current.h | |||
@@ -0,0 +1,27 @@ | |||
1 | #ifndef _ASM_POWERPC_CURRENT_H | ||
2 | #define _ASM_POWERPC_CURRENT_H | ||
3 | |||
4 | /* | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License | ||
7 | * as published by the Free Software Foundation; either version | ||
8 | * 2 of the License, or (at your option) any later version. | ||
9 | */ | ||
10 | |||
11 | struct task_struct; | ||
12 | |||
13 | #ifdef __powerpc64__ | ||
14 | #include <asm/paca.h> | ||
15 | |||
16 | #define current (get_paca()->__current) | ||
17 | |||
18 | #else | ||
19 | |||
20 | /* | ||
21 | * We keep `current' in r2 for speed. | ||
22 | */ | ||
23 | register struct task_struct *current asm ("r2"); | ||
24 | |||
25 | #endif | ||
26 | |||
27 | #endif /* _ASM_POWERPC_CURRENT_H */ | ||
diff --git a/include/asm-powerpc/eeh_event.h b/include/asm-powerpc/eeh_event.h new file mode 100644 index 000000000000..d168a30b3866 --- /dev/null +++ b/include/asm-powerpc/eeh_event.h | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * eeh_event.h | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | * | ||
18 | * Copyright (c) 2005 Linas Vepstas <linas@linas.org> | ||
19 | */ | ||
20 | |||
21 | #ifndef ASM_PPC64_EEH_EVENT_H | ||
22 | #define ASM_PPC64_EEH_EVENT_H | ||
23 | |||
24 | /** EEH event -- structure holding pci controller data that describes | ||
25 | * a change in the isolation status of a PCI slot. A pointer | ||
26 | * to this struct is passed as the data pointer in a notify callback. | ||
27 | */ | ||
28 | struct eeh_event { | ||
29 | struct list_head list; | ||
30 | struct device_node *dn; /* struct device node */ | ||
31 | struct pci_dev *dev; /* affected device */ | ||
32 | int state; | ||
33 | int time_unavail; /* milliseconds until device might be available */ | ||
34 | }; | ||
35 | |||
36 | /** | ||
37 | * eeh_send_failure_event - generate a PCI error event | ||
38 | * @dev pci device | ||
39 | * | ||
40 | * This routine builds a PCI error event which will be delivered | ||
41 | * to all listeners on the peh_notifier_chain. | ||
42 | * | ||
43 | * This routine can be called within an interrupt context; | ||
44 | * the actual event will be delivered in a normal context | ||
45 | * (from a workqueue). | ||
46 | */ | ||
47 | int eeh_send_failure_event (struct device_node *dn, | ||
48 | struct pci_dev *dev, | ||
49 | int reset_state, | ||
50 | int time_unavail); | ||
51 | |||
52 | #endif /* ASM_PPC64_EEH_EVENT_H */ | ||
diff --git a/include/asm-powerpc/firmware.h b/include/asm-powerpc/firmware.h index 806c142ae9ea..12fabbcb04f0 100644 --- a/include/asm-powerpc/firmware.h +++ b/include/asm-powerpc/firmware.h | |||
@@ -43,6 +43,7 @@ | |||
43 | #define FW_FEATURE_ISERIES (1UL<<21) | 43 | #define FW_FEATURE_ISERIES (1UL<<21) |
44 | 44 | ||
45 | enum { | 45 | enum { |
46 | #ifdef CONFIG_PPC64 | ||
46 | FW_FEATURE_PSERIES_POSSIBLE = FW_FEATURE_PFT | FW_FEATURE_TCE | | 47 | FW_FEATURE_PSERIES_POSSIBLE = FW_FEATURE_PFT | FW_FEATURE_TCE | |
47 | FW_FEATURE_SPRG0 | FW_FEATURE_DABR | FW_FEATURE_COPY | | 48 | FW_FEATURE_SPRG0 | FW_FEATURE_DABR | FW_FEATURE_COPY | |
48 | FW_FEATURE_ASR | FW_FEATURE_DEBUG | FW_FEATURE_TERM | | 49 | FW_FEATURE_ASR | FW_FEATURE_DEBUG | FW_FEATURE_TERM | |
@@ -70,6 +71,11 @@ enum { | |||
70 | FW_FEATURE_ISERIES_ALWAYS & | 71 | FW_FEATURE_ISERIES_ALWAYS & |
71 | #endif | 72 | #endif |
72 | FW_FEATURE_POSSIBLE, | 73 | FW_FEATURE_POSSIBLE, |
74 | |||
75 | #else /* CONFIG_PPC64 */ | ||
76 | FW_FEATURE_POSSIBLE = 0, | ||
77 | FW_FEATURE_ALWAYS = 0, | ||
78 | #endif | ||
73 | }; | 79 | }; |
74 | 80 | ||
75 | /* This is used to identify firmware features which are available | 81 | /* This is used to identify firmware features which are available |
diff --git a/include/asm-powerpc/futex.h b/include/asm-powerpc/futex.h index 37c94e52ab6d..f0319d50b129 100644 --- a/include/asm-powerpc/futex.h +++ b/include/asm-powerpc/futex.h | |||
@@ -7,13 +7,14 @@ | |||
7 | #include <asm/errno.h> | 7 | #include <asm/errno.h> |
8 | #include <asm/synch.h> | 8 | #include <asm/synch.h> |
9 | #include <asm/uaccess.h> | 9 | #include <asm/uaccess.h> |
10 | #include <asm/ppc_asm.h> | 10 | #include <asm/asm-compat.h> |
11 | 11 | ||
12 | #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ | 12 | #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ |
13 | __asm__ __volatile ( \ | 13 | __asm__ __volatile ( \ |
14 | SYNC_ON_SMP \ | 14 | SYNC_ON_SMP \ |
15 | "1: lwarx %0,0,%2\n" \ | 15 | "1: lwarx %0,0,%2\n" \ |
16 | insn \ | 16 | insn \ |
17 | PPC405_ERR77(0, %2) \ | ||
17 | "2: stwcx. %1,0,%2\n" \ | 18 | "2: stwcx. %1,0,%2\n" \ |
18 | "bne- 1b\n" \ | 19 | "bne- 1b\n" \ |
19 | "li %1,0\n" \ | 20 | "li %1,0\n" \ |
@@ -23,7 +24,7 @@ | |||
23 | ".previous\n" \ | 24 | ".previous\n" \ |
24 | ".section __ex_table,\"a\"\n" \ | 25 | ".section __ex_table,\"a\"\n" \ |
25 | ".align 3\n" \ | 26 | ".align 3\n" \ |
26 | DATAL " 1b,4b,2b,4b\n" \ | 27 | PPC_LONG "1b,4b,2b,4b\n" \ |
27 | ".previous" \ | 28 | ".previous" \ |
28 | : "=&r" (oldval), "=&r" (ret) \ | 29 | : "=&r" (oldval), "=&r" (ret) \ |
29 | : "b" (uaddr), "i" (-EFAULT), "1" (oparg) \ | 30 | : "b" (uaddr), "i" (-EFAULT), "1" (oparg) \ |
diff --git a/include/asm-ppc64/hvcall.h b/include/asm-powerpc/hvcall.h index ab7c3cf24888..d36da61dbc53 100644 --- a/include/asm-ppc64/hvcall.h +++ b/include/asm-powerpc/hvcall.h | |||
@@ -1,5 +1,5 @@ | |||
1 | #ifndef _PPC64_HVCALL_H | 1 | #ifndef _ASM_POWERPC_HVCALL_H |
2 | #define _PPC64_HVCALL_H | 2 | #define _ASM_POWERPC_HVCALL_H |
3 | 3 | ||
4 | #define HVSC .long 0x44000022 | 4 | #define HVSC .long 0x44000022 |
5 | 5 | ||
@@ -138,7 +138,7 @@ long plpar_hcall(unsigned long opcode, | |||
138 | */ | 138 | */ |
139 | long plpar_hcall_norets(unsigned long opcode, ...); | 139 | long plpar_hcall_norets(unsigned long opcode, ...); |
140 | 140 | ||
141 | /* | 141 | /* |
142 | * Special hcall interface for ibmveth support. | 142 | * Special hcall interface for ibmveth support. |
143 | * Takes 8 input parms. Returns a rc and stores the | 143 | * Takes 8 input parms. Returns a rc and stores the |
144 | * R4 return value in *out1. | 144 | * R4 return value in *out1. |
@@ -153,11 +153,11 @@ long plpar_hcall_8arg_2ret(unsigned long opcode, | |||
153 | unsigned long arg7, | 153 | unsigned long arg7, |
154 | unsigned long arg8, | 154 | unsigned long arg8, |
155 | unsigned long *out1); | 155 | unsigned long *out1); |
156 | 156 | ||
157 | /* plpar_hcall_4out() | 157 | /* plpar_hcall_4out() |
158 | * | 158 | * |
159 | * same as plpar_hcall except with 4 output arguments. | 159 | * same as plpar_hcall except with 4 output arguments. |
160 | * | 160 | * |
161 | */ | 161 | */ |
162 | long plpar_hcall_4out(unsigned long opcode, | 162 | long plpar_hcall_4out(unsigned long opcode, |
163 | unsigned long arg1, | 163 | unsigned long arg1, |
@@ -170,4 +170,4 @@ long plpar_hcall_4out(unsigned long opcode, | |||
170 | unsigned long *out4); | 170 | unsigned long *out4); |
171 | 171 | ||
172 | #endif /* __ASSEMBLY__ */ | 172 | #endif /* __ASSEMBLY__ */ |
173 | #endif /* _PPC64_HVCALL_H */ | 173 | #endif /* _ASM_POWERPC_HVCALL_H */ |
diff --git a/include/asm-powerpc/hw_irq.h b/include/asm-powerpc/hw_irq.h index c37b31b96337..26b89d859c56 100644 --- a/include/asm-powerpc/hw_irq.h +++ b/include/asm-powerpc/hw_irq.h | |||
@@ -12,7 +12,6 @@ | |||
12 | #include <asm/processor.h> | 12 | #include <asm/processor.h> |
13 | 13 | ||
14 | extern void timer_interrupt(struct pt_regs *); | 14 | extern void timer_interrupt(struct pt_regs *); |
15 | extern void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq); | ||
16 | 15 | ||
17 | #ifdef CONFIG_PPC_ISERIES | 16 | #ifdef CONFIG_PPC_ISERIES |
18 | 17 | ||
diff --git a/include/asm-powerpc/irq.h b/include/asm-powerpc/irq.h index b3935ea28fff..c9fbcede0ef9 100644 --- a/include/asm-powerpc/irq.h +++ b/include/asm-powerpc/irq.h | |||
@@ -429,7 +429,6 @@ extern u64 ppc64_interrupt_controller; | |||
429 | #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) | 429 | #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) |
430 | /* pedantic: these are long because they are used with set_bit --RR */ | 430 | /* pedantic: these are long because they are used with set_bit --RR */ |
431 | extern unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; | 431 | extern unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; |
432 | extern unsigned long ppc_lost_interrupts[NR_MASK_WORDS]; | ||
433 | extern atomic_t ppc_n_lost_interrupts; | 432 | extern atomic_t ppc_n_lost_interrupts; |
434 | 433 | ||
435 | #define virt_irq_create_mapping(x) (x) | 434 | #define virt_irq_create_mapping(x) (x) |
@@ -488,8 +487,8 @@ extern struct thread_info *softirq_ctx[NR_CPUS]; | |||
488 | 487 | ||
489 | extern void irq_ctx_init(void); | 488 | extern void irq_ctx_init(void); |
490 | extern void call_do_softirq(struct thread_info *tp); | 489 | extern void call_do_softirq(struct thread_info *tp); |
491 | extern int call_handle_IRQ_event(int irq, struct pt_regs *regs, | 490 | extern int call___do_IRQ(int irq, struct pt_regs *regs, |
492 | struct irqaction *action, struct thread_info *tp); | 491 | struct thread_info *tp); |
493 | 492 | ||
494 | #define __ARCH_HAS_DO_SOFTIRQ | 493 | #define __ARCH_HAS_DO_SOFTIRQ |
495 | 494 | ||
diff --git a/include/asm-ppc64/lppaca.h b/include/asm-powerpc/lppaca.h index 9e2a6c0649a0..c1bedab1515b 100644 --- a/include/asm-ppc64/lppaca.h +++ b/include/asm-powerpc/lppaca.h | |||
@@ -16,8 +16,8 @@ | |||
16 | * along with this program; if not, write to the Free Software | 16 | * along with this program; if not, write to the Free Software |
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | */ | 18 | */ |
19 | #ifndef _ASM_LPPACA_H | 19 | #ifndef _ASM_POWERPC_LPPACA_H |
20 | #define _ASM_LPPACA_H | 20 | #define _ASM_POWERPC_LPPACA_H |
21 | 21 | ||
22 | //============================================================================= | 22 | //============================================================================= |
23 | // | 23 | // |
@@ -28,8 +28,7 @@ | |||
28 | //---------------------------------------------------------------------------- | 28 | //---------------------------------------------------------------------------- |
29 | #include <asm/types.h> | 29 | #include <asm/types.h> |
30 | 30 | ||
31 | struct lppaca | 31 | struct lppaca { |
32 | { | ||
33 | //============================================================================= | 32 | //============================================================================= |
34 | // CACHE_LINE_1 0x0000 - 0x007F Contains read-only data | 33 | // CACHE_LINE_1 0x0000 - 0x007F Contains read-only data |
35 | // NOTE: The xDynXyz fields are fields that will be dynamically changed by | 34 | // NOTE: The xDynXyz fields are fields that will be dynamically changed by |
@@ -129,4 +128,4 @@ struct lppaca | |||
129 | u8 pmc_save_area[256]; // PMC interrupt Area x00-xFF | 128 | u8 pmc_save_area[256]; // PMC interrupt Area x00-xFF |
130 | }; | 129 | }; |
131 | 130 | ||
132 | #endif /* _ASM_LPPACA_H */ | 131 | #endif /* _ASM_POWERPC_LPPACA_H */ |
diff --git a/include/asm-ppc64/paca.h b/include/asm-powerpc/paca.h index bccacd6aa93a..92c765c35bd0 100644 --- a/include/asm-ppc64/paca.h +++ b/include/asm-powerpc/paca.h | |||
@@ -1,11 +1,8 @@ | |||
1 | #ifndef _PPC64_PACA_H | ||
2 | #define _PPC64_PACA_H | ||
3 | |||
4 | /* | 1 | /* |
5 | * include/asm-ppc64/paca.h | 2 | * include/asm-powerpc/paca.h |
6 | * | 3 | * |
7 | * This control block defines the PACA which defines the processor | 4 | * This control block defines the PACA which defines the processor |
8 | * specific data for each logical processor on the system. | 5 | * specific data for each logical processor on the system. |
9 | * There are some pointers defined that are utilized by PLIC. | 6 | * There are some pointers defined that are utilized by PLIC. |
10 | * | 7 | * |
11 | * C 2001 PPC 64 Team, IBM Corp | 8 | * C 2001 PPC 64 Team, IBM Corp |
@@ -14,7 +11,9 @@ | |||
14 | * modify it under the terms of the GNU General Public License | 11 | * modify it under the terms of the GNU General Public License |
15 | * as published by the Free Software Foundation; either version | 12 | * as published by the Free Software Foundation; either version |
16 | * 2 of the License, or (at your option) any later version. | 13 | * 2 of the License, or (at your option) any later version. |
17 | */ | 14 | */ |
15 | #ifndef _ASM_POWERPC_PACA_H | ||
16 | #define _ASM_POWERPC_PACA_H | ||
18 | 17 | ||
19 | #include <linux/config.h> | 18 | #include <linux/config.h> |
20 | #include <asm/types.h> | 19 | #include <asm/types.h> |
@@ -118,4 +117,4 @@ struct paca_struct { | |||
118 | 117 | ||
119 | extern struct paca_struct paca[]; | 118 | extern struct paca_struct paca[]; |
120 | 119 | ||
121 | #endif /* _PPC64_PACA_H */ | 120 | #endif /* _ASM_POWERPC_PACA_H */ |
diff --git a/include/asm-powerpc/ppc-pci.h b/include/asm-powerpc/ppc-pci.h index 13aacff755f3..9896fade98a7 100644 --- a/include/asm-powerpc/ppc-pci.h +++ b/include/asm-powerpc/ppc-pci.h | |||
@@ -26,6 +26,10 @@ extern unsigned long find_and_init_phbs(void); | |||
26 | 26 | ||
27 | extern struct pci_dev *ppc64_isabridge_dev; /* may be NULL if no ISA bus */ | 27 | extern struct pci_dev *ppc64_isabridge_dev; /* may be NULL if no ISA bus */ |
28 | 28 | ||
29 | /** Bus Unit ID macros; get low and hi 32-bits of the 64-bit BUID */ | ||
30 | #define BUID_HI(buid) ((buid) >> 32) | ||
31 | #define BUID_LO(buid) ((buid) & 0xffffffff) | ||
32 | |||
29 | /* PCI device_node operations */ | 33 | /* PCI device_node operations */ |
30 | struct device_node; | 34 | struct device_node; |
31 | typedef void *(*traverse_func)(struct device_node *me, void *data); | 35 | typedef void *(*traverse_func)(struct device_node *me, void *data); |
@@ -36,10 +40,6 @@ void pci_devs_phb_init(void); | |||
36 | void pci_devs_phb_init_dynamic(struct pci_controller *phb); | 40 | void pci_devs_phb_init_dynamic(struct pci_controller *phb); |
37 | void __devinit scan_phb(struct pci_controller *hose); | 41 | void __devinit scan_phb(struct pci_controller *hose); |
38 | 42 | ||
39 | /* PCI address cache management routines */ | ||
40 | void pci_addr_cache_insert_device(struct pci_dev *dev); | ||
41 | void pci_addr_cache_remove_device(struct pci_dev *dev); | ||
42 | |||
43 | /* From rtas_pci.h */ | 43 | /* From rtas_pci.h */ |
44 | void init_pci_config_tokens (void); | 44 | void init_pci_config_tokens (void); |
45 | unsigned long get_phb_buid (struct device_node *); | 45 | unsigned long get_phb_buid (struct device_node *); |
@@ -52,4 +52,48 @@ extern unsigned long pci_probe_only; | |||
52 | extern unsigned long pci_assign_all_buses; | 52 | extern unsigned long pci_assign_all_buses; |
53 | extern int pci_read_irq_line(struct pci_dev *pci_dev); | 53 | extern int pci_read_irq_line(struct pci_dev *pci_dev); |
54 | 54 | ||
55 | /* ---- EEH internal-use-only related routines ---- */ | ||
56 | #ifdef CONFIG_EEH | ||
57 | /** | ||
58 | * rtas_set_slot_reset -- unfreeze a frozen slot | ||
59 | * | ||
60 | * Clear the EEH-frozen condition on a slot. This routine | ||
61 | * does this by asserting the PCI #RST line for 1/8th of | ||
62 | * a second; this routine will sleep while the adapter is | ||
63 | * being reset. | ||
64 | */ | ||
65 | void rtas_set_slot_reset (struct pci_dn *); | ||
66 | |||
67 | /** | ||
68 | * eeh_restore_bars - Restore device configuration info. | ||
69 | * | ||
70 | * A reset of a PCI device will clear out its config space. | ||
71 | * This routines will restore the config space for this | ||
72 | * device, and is children, to values previously obtained | ||
73 | * from the firmware. | ||
74 | */ | ||
75 | void eeh_restore_bars(struct pci_dn *); | ||
76 | |||
77 | /** | ||
78 | * rtas_configure_bridge -- firmware initialization of pci bridge | ||
79 | * | ||
80 | * Ask the firmware to configure all PCI bridges devices | ||
81 | * located behind the indicated node. Required after a | ||
82 | * pci device reset. Does essentially the same hing as | ||
83 | * eeh_restore_bars, but for brdges, and lets firmware | ||
84 | * do the work. | ||
85 | */ | ||
86 | void rtas_configure_bridge(struct pci_dn *); | ||
87 | |||
88 | int rtas_write_config(struct pci_dn *, int where, int size, u32 val); | ||
89 | |||
90 | /** | ||
91 | * mark and clear slots: find "partition endpoint" PE and set or | ||
92 | * clear the flags for each subnode of the PE. | ||
93 | */ | ||
94 | void eeh_mark_slot (struct device_node *dn, int mode_flag); | ||
95 | void eeh_clear_slot (struct device_node *dn, int mode_flag); | ||
96 | |||
97 | #endif | ||
98 | |||
55 | #endif /* _ASM_POWERPC_PPC_PCI_H */ | 99 | #endif /* _ASM_POWERPC_PPC_PCI_H */ |
diff --git a/include/asm-powerpc/ppc_asm.h b/include/asm-powerpc/ppc_asm.h index c534ca41224b..c27baa0563fe 100644 --- a/include/asm-powerpc/ppc_asm.h +++ b/include/asm-powerpc/ppc_asm.h | |||
@@ -6,8 +6,13 @@ | |||
6 | 6 | ||
7 | #include <linux/stringify.h> | 7 | #include <linux/stringify.h> |
8 | #include <linux/config.h> | 8 | #include <linux/config.h> |
9 | #include <asm/asm-compat.h> | ||
9 | 10 | ||
10 | #ifdef __ASSEMBLY__ | 11 | #ifndef __ASSEMBLY__ |
12 | #error __FILE__ should only be used in assembler files | ||
13 | #else | ||
14 | |||
15 | #define SZL (BITS_PER_LONG/8) | ||
11 | 16 | ||
12 | /* | 17 | /* |
13 | * Macros for storing registers into and loading registers from | 18 | * Macros for storing registers into and loading registers from |
@@ -184,12 +189,6 @@ n: | |||
184 | oris reg,reg,(label)@h; \ | 189 | oris reg,reg,(label)@h; \ |
185 | ori reg,reg,(label)@l; | 190 | ori reg,reg,(label)@l; |
186 | 191 | ||
187 | /* operations for longs and pointers */ | ||
188 | #define LDL ld | ||
189 | #define STL std | ||
190 | #define CMPI cmpdi | ||
191 | #define SZL 8 | ||
192 | |||
193 | /* offsets for stack frame layout */ | 192 | /* offsets for stack frame layout */ |
194 | #define LRSAVE 16 | 193 | #define LRSAVE 16 |
195 | 194 | ||
@@ -203,12 +202,6 @@ n: | |||
203 | 202 | ||
204 | #define OFF(name) name@l | 203 | #define OFF(name) name@l |
205 | 204 | ||
206 | /* operations for longs and pointers */ | ||
207 | #define LDL lwz | ||
208 | #define STL stw | ||
209 | #define CMPI cmpwi | ||
210 | #define SZL 4 | ||
211 | |||
212 | /* offsets for stack frame layout */ | 205 | /* offsets for stack frame layout */ |
213 | #define LRSAVE 4 | 206 | #define LRSAVE 4 |
214 | 207 | ||
@@ -266,15 +259,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601) | |||
266 | #endif | 259 | #endif |
267 | 260 | ||
268 | 261 | ||
269 | #ifdef CONFIG_IBM405_ERR77 | ||
270 | #define PPC405_ERR77(ra,rb) dcbt ra, rb; | ||
271 | #define PPC405_ERR77_SYNC sync; | ||
272 | #else | ||
273 | #define PPC405_ERR77(ra,rb) | ||
274 | #define PPC405_ERR77_SYNC | ||
275 | #endif | ||
276 | |||
277 | |||
278 | #ifdef CONFIG_IBM440EP_ERR42 | 262 | #ifdef CONFIG_IBM440EP_ERR42 |
279 | #define PPC440EP_ERR42 isync | 263 | #define PPC440EP_ERR42 isync |
280 | #else | 264 | #else |
@@ -502,17 +486,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601) | |||
502 | #define N_SLINE 68 | 486 | #define N_SLINE 68 |
503 | #define N_SO 100 | 487 | #define N_SO 100 |
504 | 488 | ||
505 | #define ASM_CONST(x) x | ||
506 | #else | ||
507 | #define __ASM_CONST(x) x##UL | ||
508 | #define ASM_CONST(x) __ASM_CONST(x) | ||
509 | |||
510 | #ifdef CONFIG_PPC64 | ||
511 | #define DATAL ".llong" | ||
512 | #else | ||
513 | #define DATAL ".long" | ||
514 | #endif | ||
515 | |||
516 | #endif /* __ASSEMBLY__ */ | 489 | #endif /* __ASSEMBLY__ */ |
517 | 490 | ||
518 | #endif /* _ASM_POWERPC_PPC_ASM_H */ | 491 | #endif /* _ASM_POWERPC_PPC_ASM_H */ |
diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h index 1dc4bf7b52b3..f6f186b56b0f 100644 --- a/include/asm-powerpc/processor.h +++ b/include/asm-powerpc/processor.h | |||
@@ -17,65 +17,71 @@ | |||
17 | #include <linux/compiler.h> | 17 | #include <linux/compiler.h> |
18 | #include <asm/ptrace.h> | 18 | #include <asm/ptrace.h> |
19 | #include <asm/types.h> | 19 | #include <asm/types.h> |
20 | #ifdef CONFIG_PPC64 | ||
21 | #include <asm/systemcfg.h> | ||
22 | #endif | ||
23 | 20 | ||
24 | #ifdef CONFIG_PPC32 | 21 | /* We do _not_ want to define new machine types at all, those must die |
25 | /* 32-bit platform types */ | 22 | * in favor of using the device-tree |
26 | /* We only need to define a new _MACH_xxx for machines which are part of | 23 | * -- BenH. |
27 | * a configuration which supports more than one type of different machine. | ||
28 | * This is currently limited to CONFIG_PPC_MULTIPLATFORM and CHRP/PReP/PMac. | ||
29 | * -- Tom | ||
30 | */ | 24 | */ |
31 | #define _MACH_prep 0x00000001 | ||
32 | #define _MACH_Pmac 0x00000002 /* pmac or pmac clone (non-chrp) */ | ||
33 | #define _MACH_chrp 0x00000004 /* chrp machine */ | ||
34 | 25 | ||
35 | /* see residual.h for these */ | 26 | /* Platforms codes (to be obsoleted) */ |
27 | #define PLATFORM_PSERIES 0x0100 | ||
28 | #define PLATFORM_PSERIES_LPAR 0x0101 | ||
29 | #define PLATFORM_ISERIES_LPAR 0x0201 | ||
30 | #define PLATFORM_LPAR 0x0001 | ||
31 | #define PLATFORM_POWERMAC 0x0400 | ||
32 | #define PLATFORM_MAPLE 0x0500 | ||
33 | #define PLATFORM_PREP 0x0600 | ||
34 | #define PLATFORM_CHRP 0x0700 | ||
35 | #define PLATFORM_CELL 0x1000 | ||
36 | |||
37 | /* Compat platform codes for 32 bits */ | ||
38 | #define _MACH_prep PLATFORM_PREP | ||
39 | #define _MACH_Pmac PLATFORM_POWERMAC | ||
40 | #define _MACH_chrp PLATFORM_CHRP | ||
41 | |||
42 | /* PREP sub-platform types see residual.h for these */ | ||
36 | #define _PREP_Motorola 0x01 /* motorola prep */ | 43 | #define _PREP_Motorola 0x01 /* motorola prep */ |
37 | #define _PREP_Firm 0x02 /* firmworks prep */ | 44 | #define _PREP_Firm 0x02 /* firmworks prep */ |
38 | #define _PREP_IBM 0x00 /* ibm prep */ | 45 | #define _PREP_IBM 0x00 /* ibm prep */ |
39 | #define _PREP_Bull 0x03 /* bull prep */ | 46 | #define _PREP_Bull 0x03 /* bull prep */ |
40 | 47 | ||
41 | /* these are arbitrary */ | 48 | /* CHRP sub-platform types. These are arbitrary */ |
42 | #define _CHRP_Motorola 0x04 /* motorola chrp, the cobra */ | 49 | #define _CHRP_Motorola 0x04 /* motorola chrp, the cobra */ |
43 | #define _CHRP_IBM 0x05 /* IBM chrp, the longtrail and longtrail 2 */ | 50 | #define _CHRP_IBM 0x05 /* IBM chrp, the longtrail and longtrail 2 */ |
44 | #define _CHRP_Pegasos 0x06 /* Genesi/bplan's Pegasos and Pegasos2 */ | 51 | #define _CHRP_Pegasos 0x06 /* Genesi/bplan's Pegasos and Pegasos2 */ |
45 | 52 | ||
46 | #ifdef CONFIG_PPC_MULTIPLATFORM | 53 | #define platform_is_pseries() (_machine == PLATFORM_PSERIES || \ |
54 | _machine == PLATFORM_PSERIES_LPAR) | ||
55 | #define platform_is_lpar() (!!(_machine & PLATFORM_LPAR)) | ||
56 | |||
57 | #if defined(CONFIG_PPC_MULTIPLATFORM) | ||
47 | extern int _machine; | 58 | extern int _machine; |
48 | 59 | ||
60 | #ifdef CONFIG_PPC32 | ||
61 | |||
49 | /* what kind of prep workstation we are */ | 62 | /* what kind of prep workstation we are */ |
50 | extern int _prep_type; | 63 | extern int _prep_type; |
51 | extern int _chrp_type; | 64 | extern int _chrp_type; |
52 | 65 | ||
53 | /* | 66 | /* |
54 | * This is used to identify the board type from a given PReP board | 67 | * This is used to identify the board type from a given PReP board |
55 | * vendor. Board revision is also made available. | 68 | * vendor. Board revision is also made available. This will be moved |
69 | * elsewhere soon | ||
56 | */ | 70 | */ |
57 | extern unsigned char ucSystemType; | 71 | extern unsigned char ucSystemType; |
58 | extern unsigned char ucBoardRev; | 72 | extern unsigned char ucBoardRev; |
59 | extern unsigned char ucBoardRevMaj, ucBoardRevMin; | 73 | extern unsigned char ucBoardRevMaj, ucBoardRevMin; |
74 | |||
75 | #endif /* CONFIG_PPC32 */ | ||
76 | |||
77 | #elif defined(CONFIG_PPC_ISERIES) | ||
78 | /* | ||
79 | * iSeries is soon to become MULTIPLATFORM hopefully ... | ||
80 | */ | ||
81 | #define _machine PLATFORM_ISERIES_LPAR | ||
60 | #else | 82 | #else |
61 | #define _machine 0 | 83 | #define _machine 0 |
62 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | 84 | #endif /* CONFIG_PPC_MULTIPLATFORM */ |
63 | #endif /* CONFIG_PPC32 */ | ||
64 | |||
65 | #ifdef CONFIG_PPC64 | ||
66 | /* Platforms supported by PPC64 */ | ||
67 | #define PLATFORM_PSERIES 0x0100 | ||
68 | #define PLATFORM_PSERIES_LPAR 0x0101 | ||
69 | #define PLATFORM_ISERIES_LPAR 0x0201 | ||
70 | #define PLATFORM_LPAR 0x0001 | ||
71 | #define PLATFORM_POWERMAC 0x0400 | ||
72 | #define PLATFORM_MAPLE 0x0500 | ||
73 | #define PLATFORM_CELL 0x1000 | ||
74 | |||
75 | /* Compatibility with drivers coming from PPC32 world */ | ||
76 | #define _machine (systemcfg->platform) | ||
77 | #define _MACH_Pmac PLATFORM_POWERMAC | ||
78 | #endif | ||
79 | 85 | ||
80 | /* | 86 | /* |
81 | * Default implementation of macro that returns current | 87 | * Default implementation of macro that returns current |
diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h index 489cf4c99c21..eb392d038ed7 100644 --- a/include/asm-powerpc/reg.h +++ b/include/asm-powerpc/reg.h | |||
@@ -16,7 +16,11 @@ | |||
16 | /* Pickup Book E specific registers. */ | 16 | /* Pickup Book E specific registers. */ |
17 | #if defined(CONFIG_BOOKE) || defined(CONFIG_40x) | 17 | #if defined(CONFIG_BOOKE) || defined(CONFIG_40x) |
18 | #include <asm/reg_booke.h> | 18 | #include <asm/reg_booke.h> |
19 | #endif | 19 | #endif /* CONFIG_BOOKE || CONFIG_40x */ |
20 | |||
21 | #ifdef CONFIG_8xx | ||
22 | #include <asm/reg_8xx.h> | ||
23 | #endif /* CONFIG_8xx */ | ||
20 | 24 | ||
21 | #define MSR_SF_LG 63 /* Enable 64 bit mode */ | 25 | #define MSR_SF_LG 63 /* Enable 64 bit mode */ |
22 | #define MSR_ISF_LG 61 /* Interrupt 64b mode valid on 630 */ | 26 | #define MSR_ISF_LG 61 /* Interrupt 64b mode valid on 630 */ |
@@ -359,6 +363,7 @@ | |||
359 | #define SPRN_RPA 0x3D6 /* Required Physical Address Register */ | 363 | #define SPRN_RPA 0x3D6 /* Required Physical Address Register */ |
360 | #define SPRN_SDA 0x3BF /* Sampled Data Address Register */ | 364 | #define SPRN_SDA 0x3BF /* Sampled Data Address Register */ |
361 | #define SPRN_SDR1 0x019 /* MMU Hash Base Register */ | 365 | #define SPRN_SDR1 0x019 /* MMU Hash Base Register */ |
366 | #define SPRN_ASR 0x118 /* Address Space Register */ | ||
362 | #define SPRN_SIA 0x3BB /* Sampled Instruction Address Register */ | 367 | #define SPRN_SIA 0x3BB /* Sampled Instruction Address Register */ |
363 | #define SPRN_SPRG0 0x110 /* Special Purpose Register General 0 */ | 368 | #define SPRN_SPRG0 0x110 /* Special Purpose Register General 0 */ |
364 | #define SPRN_SPRG1 0x111 /* Special Purpose Register General 1 */ | 369 | #define SPRN_SPRG1 0x111 /* Special Purpose Register General 1 */ |
diff --git a/include/asm-ppc/cache.h b/include/asm-powerpc/reg_8xx.h index 7a157d0f4b5f..e8ea346b21d3 100644 --- a/include/asm-ppc/cache.h +++ b/include/asm-powerpc/reg_8xx.h | |||
@@ -1,49 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * include/asm-ppc/cache.h | 2 | * Contains register definitions common to PowerPC 8xx CPUs. Notice |
3 | */ | 3 | */ |
4 | #ifdef __KERNEL__ | 4 | #ifndef _ASM_POWERPC_REG_8xx_H |
5 | #ifndef __ARCH_PPC_CACHE_H | 5 | #define _ASM_POWERPC_REG_8xx_H |
6 | #define __ARCH_PPC_CACHE_H | ||
7 | 6 | ||
8 | #include <linux/config.h> | ||
9 | |||
10 | /* bytes per L1 cache line */ | ||
11 | #if defined(CONFIG_8xx) || defined(CONFIG_403GCX) | ||
12 | #define L1_CACHE_SHIFT 4 | ||
13 | #define MAX_COPY_PREFETCH 1 | ||
14 | #elif defined(CONFIG_PPC64BRIDGE) | ||
15 | #define L1_CACHE_SHIFT 7 | ||
16 | #define MAX_COPY_PREFETCH 1 | ||
17 | #else | ||
18 | #define L1_CACHE_SHIFT 5 | ||
19 | #define MAX_COPY_PREFETCH 4 | ||
20 | #endif | ||
21 | |||
22 | #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) | ||
23 | |||
24 | #define SMP_CACHE_BYTES L1_CACHE_BYTES | ||
25 | #define L1_CACHE_SHIFT_MAX 7 /* largest L1 which this arch supports */ | ||
26 | |||
27 | #define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) | ||
28 | #define L1_CACHE_PAGES 8 | ||
29 | |||
30 | #ifndef __ASSEMBLY__ | ||
31 | extern void clean_dcache_range(unsigned long start, unsigned long stop); | ||
32 | extern void flush_dcache_range(unsigned long start, unsigned long stop); | ||
33 | extern void invalidate_dcache_range(unsigned long start, unsigned long stop); | ||
34 | extern void flush_dcache_all(void); | ||
35 | #endif /* __ASSEMBLY__ */ | ||
36 | |||
37 | /* prep registers for L2 */ | ||
38 | #define CACHECRBA 0x80000823 /* Cache configuration register address */ | ||
39 | #define L2CACHE_MASK 0x03 /* Mask for 2 L2 Cache bits */ | ||
40 | #define L2CACHE_512KB 0x00 /* 512KB */ | ||
41 | #define L2CACHE_256KB 0x01 /* 256KB */ | ||
42 | #define L2CACHE_1MB 0x02 /* 1MB */ | ||
43 | #define L2CACHE_NONE 0x03 /* NONE */ | ||
44 | #define L2CACHE_PARITY 0x08 /* Mask for L2 Cache Parity Protected bit */ | ||
45 | |||
46 | #ifdef CONFIG_8xx | ||
47 | /* Cache control on the MPC8xx is provided through some additional | 7 | /* Cache control on the MPC8xx is provided through some additional |
48 | * special purpose registers. | 8 | * special purpose registers. |
49 | */ | 9 | */ |
@@ -78,7 +38,5 @@ extern void flush_dcache_all(void); | |||
78 | 38 | ||
79 | #define DC_DFWT 0x40000000 /* Data cache is forced write through */ | 39 | #define DC_DFWT 0x40000000 /* Data cache is forced write through */ |
80 | #define DC_LES 0x20000000 /* Caches are little endian mode */ | 40 | #define DC_LES 0x20000000 /* Caches are little endian mode */ |
81 | #endif /* CONFIG_8xx */ | ||
82 | 41 | ||
83 | #endif | 42 | #endif /* _ASM_POWERPC_REG_8xx_H */ |
84 | #endif /* __KERNEL__ */ | ||
diff --git a/include/asm-ppc/signal.h b/include/asm-powerpc/signal.h index caf6ede3710f..694c8d2dab87 100644 --- a/include/asm-ppc/signal.h +++ b/include/asm-powerpc/signal.h | |||
@@ -1,18 +1,11 @@ | |||
1 | #ifndef _ASMPPC_SIGNAL_H | 1 | #ifndef _ASM_POWERPC_SIGNAL_H |
2 | #define _ASMPPC_SIGNAL_H | 2 | #define _ASM_POWERPC_SIGNAL_H |
3 | 3 | ||
4 | #ifdef __KERNEL__ | ||
5 | #include <linux/types.h> | 4 | #include <linux/types.h> |
6 | #endif /* __KERNEL__ */ | 5 | #include <linux/config.h> |
7 | |||
8 | /* Avoid too many header ordering problems. */ | ||
9 | struct siginfo; | ||
10 | |||
11 | /* Most things should be clean enough to redefine this at will, if care | ||
12 | is taken to make libc match. */ | ||
13 | 6 | ||
14 | #define _NSIG 64 | 7 | #define _NSIG 64 |
15 | #define _NSIG_BPW 32 | 8 | #define _NSIG_BPW BITS_PER_LONG |
16 | #define _NSIG_WORDS (_NSIG / _NSIG_BPW) | 9 | #define _NSIG_WORDS (_NSIG / _NSIG_BPW) |
17 | 10 | ||
18 | typedef unsigned long old_sigset_t; /* at least 32 bits */ | 11 | typedef unsigned long old_sigset_t; /* at least 32 bits */ |
@@ -77,19 +70,19 @@ typedef struct { | |||
77 | * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single | 70 | * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single |
78 | * Unix names RESETHAND and NODEFER respectively. | 71 | * Unix names RESETHAND and NODEFER respectively. |
79 | */ | 72 | */ |
80 | #define SA_NOCLDSTOP 0x00000001 | 73 | #define SA_NOCLDSTOP 0x00000001U |
81 | #define SA_NOCLDWAIT 0x00000002 | 74 | #define SA_NOCLDWAIT 0x00000002U |
82 | #define SA_SIGINFO 0x00000004 | 75 | #define SA_SIGINFO 0x00000004U |
83 | #define SA_ONSTACK 0x08000000 | 76 | #define SA_ONSTACK 0x08000000U |
84 | #define SA_RESTART 0x10000000 | 77 | #define SA_RESTART 0x10000000U |
85 | #define SA_NODEFER 0x40000000 | 78 | #define SA_NODEFER 0x40000000U |
86 | #define SA_RESETHAND 0x80000000 | 79 | #define SA_RESETHAND 0x80000000U |
87 | 80 | ||
88 | #define SA_NOMASK SA_NODEFER | 81 | #define SA_NOMASK SA_NODEFER |
89 | #define SA_ONESHOT SA_RESETHAND | 82 | #define SA_ONESHOT SA_RESETHAND |
90 | #define SA_INTERRUPT 0x20000000 /* dummy -- ignored */ | 83 | #define SA_INTERRUPT 0x20000000u /* dummy -- ignored */ |
91 | 84 | ||
92 | #define SA_RESTORER 0x04000000 | 85 | #define SA_RESTORER 0x04000000U |
93 | 86 | ||
94 | /* | 87 | /* |
95 | * sigaltstack controls | 88 | * sigaltstack controls |
@@ -127,10 +120,13 @@ typedef struct sigaltstack { | |||
127 | } stack_t; | 120 | } stack_t; |
128 | 121 | ||
129 | #ifdef __KERNEL__ | 122 | #ifdef __KERNEL__ |
130 | #include <asm/sigcontext.h> | 123 | struct pt_regs; |
124 | extern int do_signal(sigset_t *oldset, struct pt_regs *regs); | ||
125 | extern int do_signal32(sigset_t *oldset, struct pt_regs *regs); | ||
131 | #define ptrace_signal_deliver(regs, cookie) do { } while (0) | 126 | #define ptrace_signal_deliver(regs, cookie) do { } while (0) |
132 | #endif /* __KERNEL__ */ | 127 | #endif /* __KERNEL__ */ |
133 | 128 | ||
129 | #ifndef __powerpc64__ | ||
134 | /* | 130 | /* |
135 | * These are parameters to dbg_sigreturn syscall. They enable or | 131 | * These are parameters to dbg_sigreturn syscall. They enable or |
136 | * disable certain debugging things that can be done from signal | 132 | * disable certain debugging things that can be done from signal |
@@ -149,5 +145,6 @@ struct sig_dbg_op { | |||
149 | 145 | ||
150 | /* Enable or disable branch tracing. The value sets the state. */ | 146 | /* Enable or disable branch tracing. The value sets the state. */ |
151 | #define SIG_DBG_BRANCH_TRACING 2 | 147 | #define SIG_DBG_BRANCH_TRACING 2 |
148 | #endif /* ! __powerpc64__ */ | ||
152 | 149 | ||
153 | #endif | 150 | #endif /* _ASM_POWERPC_SIGNAL_H */ |
diff --git a/include/asm-powerpc/sparsemem.h b/include/asm-powerpc/sparsemem.h index 1c95ab99deb3..58d2aab416f8 100644 --- a/include/asm-powerpc/sparsemem.h +++ b/include/asm-powerpc/sparsemem.h | |||
@@ -11,6 +11,10 @@ | |||
11 | #define MAX_PHYSADDR_BITS 38 | 11 | #define MAX_PHYSADDR_BITS 38 |
12 | #define MAX_PHYSMEM_BITS 36 | 12 | #define MAX_PHYSMEM_BITS 36 |
13 | 13 | ||
14 | #ifdef CONFIG_MEMORY_HOTPLUG | ||
15 | extern void create_section_mapping(unsigned long start, unsigned long end); | ||
16 | #endif /* CONFIG_MEMORY_HOTPLUG */ | ||
17 | |||
14 | #endif /* CONFIG_SPARSEMEM */ | 18 | #endif /* CONFIG_SPARSEMEM */ |
15 | 19 | ||
16 | #endif /* _ASM_POWERPC_SPARSEMEM_H */ | 20 | #endif /* _ASM_POWERPC_SPARSEMEM_H */ |
diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h index 3536a5cd7a2d..5341b75c75cb 100644 --- a/include/asm-powerpc/system.h +++ b/include/asm-powerpc/system.h | |||
@@ -8,7 +8,6 @@ | |||
8 | #include <linux/kernel.h> | 8 | #include <linux/kernel.h> |
9 | 9 | ||
10 | #include <asm/hw_irq.h> | 10 | #include <asm/hw_irq.h> |
11 | #include <asm/ppc_asm.h> | ||
12 | #include <asm/atomic.h> | 11 | #include <asm/atomic.h> |
13 | 12 | ||
14 | /* | 13 | /* |
@@ -180,6 +179,7 @@ extern struct task_struct *_switch(struct thread_struct *prev, | |||
180 | extern unsigned int rtas_data; | 179 | extern unsigned int rtas_data; |
181 | extern int mem_init_done; /* set on boot once kmalloc can be called */ | 180 | extern int mem_init_done; /* set on boot once kmalloc can be called */ |
182 | extern unsigned long memory_limit; | 181 | extern unsigned long memory_limit; |
182 | extern unsigned long klimit; | ||
183 | 183 | ||
184 | extern int powersave_nap; /* set if nap mode can be used in idle loop */ | 184 | extern int powersave_nap; /* set if nap mode can be used in idle loop */ |
185 | 185 | ||
diff --git a/include/asm-ppc64/systemcfg.h b/include/asm-powerpc/systemcfg.h index 9b86b53129aa..36b5cbe466f1 100644 --- a/include/asm-ppc64/systemcfg.h +++ b/include/asm-powerpc/systemcfg.h | |||
@@ -1,7 +1,7 @@ | |||
1 | #ifndef _SYSTEMCFG_H | 1 | #ifndef _SYSTEMCFG_H |
2 | #define _SYSTEMCFG_H | 2 | #define _SYSTEMCFG_H |
3 | 3 | ||
4 | /* | 4 | /* |
5 | * Copyright (C) 2002 Peter Bergner <bergner@vnet.ibm.com>, IBM | 5 | * Copyright (C) 2002 Peter Bergner <bergner@vnet.ibm.com>, IBM |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
@@ -12,7 +12,7 @@ | |||
12 | 12 | ||
13 | /* Change Activity: | 13 | /* Change Activity: |
14 | * 2002/09/30 : bergner : Created | 14 | * 2002/09/30 : bergner : Created |
15 | * End Change Activity | 15 | * End Change Activity |
16 | */ | 16 | */ |
17 | 17 | ||
18 | /* | 18 | /* |
@@ -56,7 +56,7 @@ struct systemcfg { | |||
56 | }; | 56 | }; |
57 | 57 | ||
58 | #ifdef __KERNEL__ | 58 | #ifdef __KERNEL__ |
59 | extern struct systemcfg *systemcfg; | 59 | extern struct systemcfg *_systemcfg; /* to be renamed */ |
60 | #endif | 60 | #endif |
61 | 61 | ||
62 | #endif /* __ASSEMBLY__ */ | 62 | #endif /* __ASSEMBLY__ */ |
diff --git a/include/asm-ppc64/tce.h b/include/asm-powerpc/tce.h index d40b6b42ab35..d099d5200f9b 100644 --- a/include/asm-ppc64/tce.h +++ b/include/asm-powerpc/tce.h | |||
@@ -18,8 +18,8 @@ | |||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #ifndef _ASM_TCE_H | 21 | #ifndef _ASM_POWERPC_TCE_H |
22 | #define _ASM_TCE_H | 22 | #define _ASM_POWERPC_TCE_H |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * Tces come in two formats, one for the virtual bus and a different | 25 | * Tces come in two formats, one for the virtual bus and a different |
@@ -61,4 +61,4 @@ union tce_entry { | |||
61 | }; | 61 | }; |
62 | 62 | ||
63 | 63 | ||
64 | #endif | 64 | #endif /* _ASM_POWERPC_TCE_H */ |
diff --git a/include/asm-powerpc/uaccess.h b/include/asm-powerpc/uaccess.h index 33af730f0d19..3872e924cdd6 100644 --- a/include/asm-powerpc/uaccess.h +++ b/include/asm-powerpc/uaccess.h | |||
@@ -120,14 +120,6 @@ struct exception_table_entry { | |||
120 | 120 | ||
121 | extern long __put_user_bad(void); | 121 | extern long __put_user_bad(void); |
122 | 122 | ||
123 | #ifdef __powerpc64__ | ||
124 | #define __EX_TABLE_ALIGN "3" | ||
125 | #define __EX_TABLE_TYPE "llong" | ||
126 | #else | ||
127 | #define __EX_TABLE_ALIGN "2" | ||
128 | #define __EX_TABLE_TYPE "long" | ||
129 | #endif | ||
130 | |||
131 | /* | 123 | /* |
132 | * We don't tell gcc that we are accessing memory, but this is OK | 124 | * We don't tell gcc that we are accessing memory, but this is OK |
133 | * because we do not write to any memory gcc knows about, so there | 125 | * because we do not write to any memory gcc knows about, so there |
@@ -142,11 +134,12 @@ extern long __put_user_bad(void); | |||
142 | " b 2b\n" \ | 134 | " b 2b\n" \ |
143 | ".previous\n" \ | 135 | ".previous\n" \ |
144 | ".section __ex_table,\"a\"\n" \ | 136 | ".section __ex_table,\"a\"\n" \ |
145 | " .align " __EX_TABLE_ALIGN "\n" \ | 137 | " .balign %5\n" \ |
146 | " ."__EX_TABLE_TYPE" 1b,3b\n" \ | 138 | PPC_LONG "1b,3b\n" \ |
147 | ".previous" \ | 139 | ".previous" \ |
148 | : "=r" (err) \ | 140 | : "=r" (err) \ |
149 | : "r" (x), "b" (addr), "i" (-EFAULT), "0" (err)) | 141 | : "r" (x), "b" (addr), "i" (-EFAULT), "0" (err),\ |
142 | "i"(sizeof(unsigned long))) | ||
150 | 143 | ||
151 | #ifdef __powerpc64__ | 144 | #ifdef __powerpc64__ |
152 | #define __put_user_asm2(x, ptr, retval) \ | 145 | #define __put_user_asm2(x, ptr, retval) \ |
@@ -162,12 +155,13 @@ extern long __put_user_bad(void); | |||
162 | " b 3b\n" \ | 155 | " b 3b\n" \ |
163 | ".previous\n" \ | 156 | ".previous\n" \ |
164 | ".section __ex_table,\"a\"\n" \ | 157 | ".section __ex_table,\"a\"\n" \ |
165 | " .align " __EX_TABLE_ALIGN "\n" \ | 158 | " .balign %5\n" \ |
166 | " ." __EX_TABLE_TYPE " 1b,4b\n" \ | 159 | PPC_LONG "1b,4b\n" \ |
167 | " ." __EX_TABLE_TYPE " 2b,4b\n" \ | 160 | PPC_LONG "2b,4b\n" \ |
168 | ".previous" \ | 161 | ".previous" \ |
169 | : "=r" (err) \ | 162 | : "=r" (err) \ |
170 | : "r" (x), "b" (addr), "i" (-EFAULT), "0" (err)) | 163 | : "r" (x), "b" (addr), "i" (-EFAULT), "0" (err),\ |
164 | "i"(sizeof(unsigned long))) | ||
171 | #endif /* __powerpc64__ */ | 165 | #endif /* __powerpc64__ */ |
172 | 166 | ||
173 | #define __put_user_size(x, ptr, size, retval) \ | 167 | #define __put_user_size(x, ptr, size, retval) \ |
@@ -213,11 +207,12 @@ extern long __get_user_bad(void); | |||
213 | " b 2b\n" \ | 207 | " b 2b\n" \ |
214 | ".previous\n" \ | 208 | ".previous\n" \ |
215 | ".section __ex_table,\"a\"\n" \ | 209 | ".section __ex_table,\"a\"\n" \ |
216 | " .align "__EX_TABLE_ALIGN "\n" \ | 210 | " .balign %5\n" \ |
217 | " ." __EX_TABLE_TYPE " 1b,3b\n" \ | 211 | PPC_LONG "1b,3b\n" \ |
218 | ".previous" \ | 212 | ".previous" \ |
219 | : "=r" (err), "=r" (x) \ | 213 | : "=r" (err), "=r" (x) \ |
220 | : "b" (addr), "i" (-EFAULT), "0" (err)) | 214 | : "b" (addr), "i" (-EFAULT), "0" (err), \ |
215 | "i"(sizeof(unsigned long))) | ||
221 | 216 | ||
222 | #ifdef __powerpc64__ | 217 | #ifdef __powerpc64__ |
223 | #define __get_user_asm2(x, addr, err) \ | 218 | #define __get_user_asm2(x, addr, err) \ |
@@ -235,12 +230,13 @@ extern long __get_user_bad(void); | |||
235 | " b 3b\n" \ | 230 | " b 3b\n" \ |
236 | ".previous\n" \ | 231 | ".previous\n" \ |
237 | ".section __ex_table,\"a\"\n" \ | 232 | ".section __ex_table,\"a\"\n" \ |
238 | " .align " __EX_TABLE_ALIGN "\n" \ | 233 | " .balign %5\n" \ |
239 | " ." __EX_TABLE_TYPE " 1b,4b\n" \ | 234 | PPC_LONG "1b,4b\n" \ |
240 | " ." __EX_TABLE_TYPE " 2b,4b\n" \ | 235 | PPC_LONG "2b,4b\n" \ |
241 | ".previous" \ | 236 | ".previous" \ |
242 | : "=r" (err), "=&r" (x) \ | 237 | : "=r" (err), "=&r" (x) \ |
243 | : "b" (addr), "i" (-EFAULT), "0" (err)) | 238 | : "b" (addr), "i" (-EFAULT), "0" (err), \ |
239 | "i"(sizeof(unsigned long))) | ||
244 | #endif /* __powerpc64__ */ | 240 | #endif /* __powerpc64__ */ |
245 | 241 | ||
246 | #define __get_user_size(x, ptr, size, retval) \ | 242 | #define __get_user_size(x, ptr, size, retval) \ |
diff --git a/include/asm-powerpc/xmon.h b/include/asm-powerpc/xmon.h index ace2072d4a83..43f7129984c7 100644 --- a/include/asm-powerpc/xmon.h +++ b/include/asm-powerpc/xmon.h | |||
@@ -7,7 +7,6 @@ struct pt_regs; | |||
7 | extern int xmon(struct pt_regs *excp); | 7 | extern int xmon(struct pt_regs *excp); |
8 | extern void xmon_printf(const char *fmt, ...); | 8 | extern void xmon_printf(const char *fmt, ...); |
9 | extern void xmon_init(int); | 9 | extern void xmon_init(int); |
10 | extern void xmon_map_scc(void); | ||
11 | 10 | ||
12 | #endif | 11 | #endif |
13 | #endif | 12 | #endif |
diff --git a/include/asm-ppc/cacheflush.h b/include/asm-ppc/cacheflush.h deleted file mode 100644 index 6a243efb3317..000000000000 --- a/include/asm-ppc/cacheflush.h +++ /dev/null | |||
@@ -1,49 +0,0 @@ | |||
1 | /* | ||
2 | * include/asm-ppc/cacheflush.h | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | */ | ||
9 | #ifdef __KERNEL__ | ||
10 | #ifndef _PPC_CACHEFLUSH_H | ||
11 | #define _PPC_CACHEFLUSH_H | ||
12 | |||
13 | #include <linux/mm.h> | ||
14 | |||
15 | /* | ||
16 | * No cache flushing is required when address mappings are | ||
17 | * changed, because the caches on PowerPCs are physically | ||
18 | * addressed. -- paulus | ||
19 | * Also, when SMP we use the coherency (M) bit of the | ||
20 | * BATs and PTEs. -- Cort | ||
21 | */ | ||
22 | #define flush_cache_all() do { } while (0) | ||
23 | #define flush_cache_mm(mm) do { } while (0) | ||
24 | #define flush_cache_range(vma, a, b) do { } while (0) | ||
25 | #define flush_cache_page(vma, p, pfn) do { } while (0) | ||
26 | #define flush_icache_page(vma, page) do { } while (0) | ||
27 | #define flush_cache_vmap(start, end) do { } while (0) | ||
28 | #define flush_cache_vunmap(start, end) do { } while (0) | ||
29 | |||
30 | extern void flush_dcache_page(struct page *page); | ||
31 | #define flush_dcache_mmap_lock(mapping) do { } while (0) | ||
32 | #define flush_dcache_mmap_unlock(mapping) do { } while (0) | ||
33 | |||
34 | extern void flush_icache_range(unsigned long, unsigned long); | ||
35 | extern void flush_icache_user_range(struct vm_area_struct *vma, | ||
36 | struct page *page, unsigned long addr, int len); | ||
37 | |||
38 | #define copy_to_user_page(vma, page, vaddr, dst, src, len) \ | ||
39 | do { memcpy(dst, src, len); \ | ||
40 | flush_icache_user_range(vma, page, vaddr, len); \ | ||
41 | } while (0) | ||
42 | #define copy_from_user_page(vma, page, vaddr, dst, src, len) \ | ||
43 | memcpy(dst, src, len) | ||
44 | |||
45 | extern void __flush_dcache_icache(void *page_va); | ||
46 | extern void __flush_dcache_icache_phys(unsigned long physaddr); | ||
47 | extern void flush_dcache_icache_page(struct page *page); | ||
48 | #endif /* _PPC_CACHEFLUSH_H */ | ||
49 | #endif /* __KERNEL__ */ | ||
diff --git a/include/asm-ppc/current.h b/include/asm-ppc/current.h deleted file mode 100644 index 8d41501ba10d..000000000000 --- a/include/asm-ppc/current.h +++ /dev/null | |||
@@ -1,11 +0,0 @@ | |||
1 | #ifdef __KERNEL__ | ||
2 | #ifndef _PPC_CURRENT_H | ||
3 | #define _PPC_CURRENT_H | ||
4 | |||
5 | /* | ||
6 | * We keep `current' in r2 for speed. | ||
7 | */ | ||
8 | register struct task_struct *current asm ("r2"); | ||
9 | |||
10 | #endif /* !(_PPC_CURRENT_H) */ | ||
11 | #endif /* __KERNEL__ */ | ||
diff --git a/include/asm-ppc64/cache.h b/include/asm-ppc64/cache.h deleted file mode 100644 index 92140a7efbd1..000000000000 --- a/include/asm-ppc64/cache.h +++ /dev/null | |||
@@ -1,36 +0,0 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or | ||
3 | * modify it under the terms of the GNU General Public License | ||
4 | * as published by the Free Software Foundation; either version | ||
5 | * 2 of the License, or (at your option) any later version. | ||
6 | */ | ||
7 | #ifndef __ARCH_PPC64_CACHE_H | ||
8 | #define __ARCH_PPC64_CACHE_H | ||
9 | |||
10 | #include <asm/types.h> | ||
11 | |||
12 | /* bytes per L1 cache line */ | ||
13 | #define L1_CACHE_SHIFT 7 | ||
14 | #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) | ||
15 | |||
16 | #define SMP_CACHE_BYTES L1_CACHE_BYTES | ||
17 | #define L1_CACHE_SHIFT_MAX 7 /* largest L1 which this arch supports */ | ||
18 | |||
19 | #ifndef __ASSEMBLY__ | ||
20 | |||
21 | struct ppc64_caches { | ||
22 | u32 dsize; /* L1 d-cache size */ | ||
23 | u32 dline_size; /* L1 d-cache line size */ | ||
24 | u32 log_dline_size; | ||
25 | u32 dlines_per_page; | ||
26 | u32 isize; /* L1 i-cache size */ | ||
27 | u32 iline_size; /* L1 i-cache line size */ | ||
28 | u32 log_iline_size; | ||
29 | u32 ilines_per_page; | ||
30 | }; | ||
31 | |||
32 | extern struct ppc64_caches ppc64_caches; | ||
33 | |||
34 | #endif | ||
35 | |||
36 | #endif | ||
diff --git a/include/asm-ppc64/current.h b/include/asm-ppc64/current.h deleted file mode 100644 index 52ddc60c8b65..000000000000 --- a/include/asm-ppc64/current.h +++ /dev/null | |||
@@ -1,16 +0,0 @@ | |||
1 | #ifndef _PPC64_CURRENT_H | ||
2 | #define _PPC64_CURRENT_H | ||
3 | |||
4 | #include <asm/paca.h> | ||
5 | |||
6 | /* | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #define get_current() (get_paca()->__current) | ||
14 | #define current get_current() | ||
15 | |||
16 | #endif /* !(_PPC64_CURRENT_H) */ | ||
diff --git a/include/asm-ppc64/eeh.h b/include/asm-ppc64/eeh.h index 40c8eb57493e..89f26ab31908 100644 --- a/include/asm-ppc64/eeh.h +++ b/include/asm-ppc64/eeh.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * eeh.h | 2 | * eeh.h |
3 | * Copyright (C) 2001 Dave Engebretsen & Todd Inglett IBM Corporation. | 3 | * Copyright (C) 2001 Dave Engebretsen & Todd Inglett IBM Corporation. |
4 | * | 4 | * |
@@ -6,12 +6,12 @@ | |||
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
7 | * the Free Software Foundation; either version 2 of the License, or | 7 | * the Free Software Foundation; either version 2 of the License, or |
8 | * (at your option) any later version. | 8 | * (at your option) any later version. |
9 | * | 9 | * |
10 | * This program is distributed in the hope that it will be useful, | 10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU General Public License | 15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program; if not, write to the Free Software | 16 | * along with this program; if not, write to the Free Software |
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
@@ -27,8 +27,6 @@ | |||
27 | 27 | ||
28 | struct pci_dev; | 28 | struct pci_dev; |
29 | struct device_node; | 29 | struct device_node; |
30 | struct device_node; | ||
31 | struct notifier_block; | ||
32 | 30 | ||
33 | #ifdef CONFIG_EEH | 31 | #ifdef CONFIG_EEH |
34 | 32 | ||
@@ -37,6 +35,10 @@ struct notifier_block; | |||
37 | #define EEH_MODE_NOCHECK (1<<1) | 35 | #define EEH_MODE_NOCHECK (1<<1) |
38 | #define EEH_MODE_ISOLATED (1<<2) | 36 | #define EEH_MODE_ISOLATED (1<<2) |
39 | 37 | ||
38 | /* Max number of EEH freezes allowed before we consider the device | ||
39 | * to be permanently disabled. */ | ||
40 | #define EEH_MAX_ALLOWED_FREEZES 5 | ||
41 | |||
40 | void __init eeh_init(void); | 42 | void __init eeh_init(void); |
41 | unsigned long eeh_check_failure(const volatile void __iomem *token, | 43 | unsigned long eeh_check_failure(const volatile void __iomem *token, |
42 | unsigned long val); | 44 | unsigned long val); |
@@ -59,36 +61,14 @@ void eeh_add_device_late(struct pci_dev *); | |||
59 | * eeh_remove_device - undo EEH setup for the indicated pci device | 61 | * eeh_remove_device - undo EEH setup for the indicated pci device |
60 | * @dev: pci device to be removed | 62 | * @dev: pci device to be removed |
61 | * | 63 | * |
62 | * This routine should be when a device is removed from a running | 64 | * This routine should be called when a device is removed from |
63 | * system (e.g. by hotplug or dlpar). | 65 | * a running system (e.g. by hotplug or dlpar). It unregisters |
66 | * the PCI device from the EEH subsystem. I/O errors affecting | ||
67 | * this device will no longer be detected after this call; thus, | ||
68 | * i/o errors affecting this slot may leave this device unusable. | ||
64 | */ | 69 | */ |
65 | void eeh_remove_device(struct pci_dev *); | 70 | void eeh_remove_device(struct pci_dev *); |
66 | 71 | ||
67 | #define EEH_DISABLE 0 | ||
68 | #define EEH_ENABLE 1 | ||
69 | #define EEH_RELEASE_LOADSTORE 2 | ||
70 | #define EEH_RELEASE_DMA 3 | ||
71 | |||
72 | /** | ||
73 | * Notifier event flags. | ||
74 | */ | ||
75 | #define EEH_NOTIFY_FREEZE 1 | ||
76 | |||
77 | /** EEH event -- structure holding pci slot data that describes | ||
78 | * a change in the isolation status of a PCI slot. A pointer | ||
79 | * to this struct is passed as the data pointer in a notify callback. | ||
80 | */ | ||
81 | struct eeh_event { | ||
82 | struct list_head list; | ||
83 | struct pci_dev *dev; | ||
84 | struct device_node *dn; | ||
85 | int reset_state; | ||
86 | }; | ||
87 | |||
88 | /** Register to find out about EEH events. */ | ||
89 | int eeh_register_notifier(struct notifier_block *nb); | ||
90 | int eeh_unregister_notifier(struct notifier_block *nb); | ||
91 | |||
92 | /** | 72 | /** |
93 | * EEH_POSSIBLE_ERROR() -- test for possible MMIO failure. | 73 | * EEH_POSSIBLE_ERROR() -- test for possible MMIO failure. |
94 | * | 74 | * |
@@ -129,7 +109,7 @@ static inline void eeh_remove_device(struct pci_dev *dev) { } | |||
129 | #define EEH_IO_ERROR_VALUE(size) (-1UL) | 109 | #define EEH_IO_ERROR_VALUE(size) (-1UL) |
130 | #endif /* CONFIG_EEH */ | 110 | #endif /* CONFIG_EEH */ |
131 | 111 | ||
132 | /* | 112 | /* |
133 | * MMIO read/write operations with EEH support. | 113 | * MMIO read/write operations with EEH support. |
134 | */ | 114 | */ |
135 | static inline u8 eeh_readb(const volatile void __iomem *addr) | 115 | static inline u8 eeh_readb(const volatile void __iomem *addr) |
diff --git a/include/asm-ppc64/mmu.h b/include/asm-ppc64/mmu.h index 4c18a5cb69f5..1a7e0afa2dc6 100644 --- a/include/asm-ppc64/mmu.h +++ b/include/asm-ppc64/mmu.h | |||
@@ -14,7 +14,7 @@ | |||
14 | #define _PPC64_MMU_H_ | 14 | #define _PPC64_MMU_H_ |
15 | 15 | ||
16 | #include <linux/config.h> | 16 | #include <linux/config.h> |
17 | #include <asm/ppc_asm.h> /* for ASM_CONST */ | 17 | #include <asm/asm-compat.h> |
18 | #include <asm/page.h> | 18 | #include <asm/page.h> |
19 | 19 | ||
20 | /* | 20 | /* |
@@ -224,9 +224,12 @@ extern int htab_bolt_mapping(unsigned long vstart, unsigned long vend, | |||
224 | unsigned long pstart, unsigned long mode, | 224 | unsigned long pstart, unsigned long mode, |
225 | int psize); | 225 | int psize); |
226 | 226 | ||
227 | extern void htab_initialize(void); | ||
228 | extern void htab_initialize_secondary(void); | ||
227 | extern void hpte_init_native(void); | 229 | extern void hpte_init_native(void); |
228 | extern void hpte_init_lpar(void); | 230 | extern void hpte_init_lpar(void); |
229 | extern void hpte_init_iSeries(void); | 231 | extern void hpte_init_iSeries(void); |
232 | extern void mm_init_ppc64(void); | ||
230 | 233 | ||
231 | extern long pSeries_lpar_hpte_insert(unsigned long hpte_group, | 234 | extern long pSeries_lpar_hpte_insert(unsigned long hpte_group, |
232 | unsigned long va, unsigned long prpn, | 235 | unsigned long va, unsigned long prpn, |
@@ -245,6 +248,7 @@ extern long iSeries_hpte_insert(unsigned long hpte_group, | |||
245 | 248 | ||
246 | extern void stabs_alloc(void); | 249 | extern void stabs_alloc(void); |
247 | extern void slb_initialize(void); | 250 | extern void slb_initialize(void); |
251 | extern void stab_initialize(unsigned long stab); | ||
248 | 252 | ||
249 | #endif /* __ASSEMBLY__ */ | 253 | #endif /* __ASSEMBLY__ */ |
250 | 254 | ||
diff --git a/include/asm-ppc64/mmzone.h b/include/asm-ppc64/mmzone.h index 80a708e7093a..15e777ce0f4a 100644 --- a/include/asm-ppc64/mmzone.h +++ b/include/asm-ppc64/mmzone.h | |||
@@ -33,6 +33,9 @@ extern int numa_cpu_lookup_table[]; | |||
33 | extern char *numa_memory_lookup_table; | 33 | extern char *numa_memory_lookup_table; |
34 | extern cpumask_t numa_cpumask_lookup_table[]; | 34 | extern cpumask_t numa_cpumask_lookup_table[]; |
35 | extern int nr_cpus_in_node[]; | 35 | extern int nr_cpus_in_node[]; |
36 | #ifdef CONFIG_MEMORY_HOTPLUG | ||
37 | extern unsigned long max_pfn; | ||
38 | #endif | ||
36 | 39 | ||
37 | /* 16MB regions */ | 40 | /* 16MB regions */ |
38 | #define MEMORY_INCREMENT_SHIFT 24 | 41 | #define MEMORY_INCREMENT_SHIFT 24 |
@@ -45,6 +48,11 @@ static inline int pa_to_nid(unsigned long pa) | |||
45 | { | 48 | { |
46 | int nid; | 49 | int nid; |
47 | 50 | ||
51 | #ifdef CONFIG_MEMORY_HOTPLUG | ||
52 | /* kludge hot added sections default to node 0 */ | ||
53 | if (pa >= (max_pfn << PAGE_SHIFT)) | ||
54 | return 0; | ||
55 | #endif | ||
48 | nid = numa_memory_lookup_table[pa >> MEMORY_INCREMENT_SHIFT]; | 56 | nid = numa_memory_lookup_table[pa >> MEMORY_INCREMENT_SHIFT]; |
49 | 57 | ||
50 | #ifdef DEBUG_NUMA | 58 | #ifdef DEBUG_NUMA |
diff --git a/include/asm-ppc64/page.h b/include/asm-ppc64/page.h index 82ce187e5be8..e32f1187aa29 100644 --- a/include/asm-ppc64/page.h +++ b/include/asm-ppc64/page.h | |||
@@ -11,7 +11,7 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/config.h> | 13 | #include <linux/config.h> |
14 | #include <asm/ppc_asm.h> /* for ASM_CONST */ | 14 | #include <asm/asm-compat.h> |
15 | 15 | ||
16 | /* | 16 | /* |
17 | * We support either 4k or 64k software page size. When using 64k pages | 17 | * We support either 4k or 64k software page size. When using 64k pages |
diff --git a/include/asm-ppc64/pci-bridge.h b/include/asm-ppc64/pci-bridge.h index 60cf8c838af0..efbdaece0cf0 100644 --- a/include/asm-ppc64/pci-bridge.h +++ b/include/asm-ppc64/pci-bridge.h | |||
@@ -63,7 +63,6 @@ struct pci_dn { | |||
63 | int devfn; /* for pci devices */ | 63 | int devfn; /* for pci devices */ |
64 | int eeh_mode; /* See eeh.h for possible EEH_MODEs */ | 64 | int eeh_mode; /* See eeh.h for possible EEH_MODEs */ |
65 | int eeh_config_addr; | 65 | int eeh_config_addr; |
66 | int eeh_capable; /* from firmware */ | ||
67 | int eeh_check_count; /* # times driver ignored error */ | 66 | int eeh_check_count; /* # times driver ignored error */ |
68 | int eeh_freeze_count; /* # times this device froze up. */ | 67 | int eeh_freeze_count; /* # times this device froze up. */ |
69 | int eeh_is_bridge; /* device is pci-to-pci bridge */ | 68 | int eeh_is_bridge; /* device is pci-to-pci bridge */ |
diff --git a/include/asm-ppc64/pgalloc.h b/include/asm-ppc64/pgalloc.h index 98da0e4262bd..dcf3622d1946 100644 --- a/include/asm-ppc64/pgalloc.h +++ b/include/asm-ppc64/pgalloc.h | |||
@@ -10,8 +10,8 @@ extern kmem_cache_t *pgtable_cache[]; | |||
10 | 10 | ||
11 | #ifdef CONFIG_PPC_64K_PAGES | 11 | #ifdef CONFIG_PPC_64K_PAGES |
12 | #define PTE_CACHE_NUM 0 | 12 | #define PTE_CACHE_NUM 0 |
13 | #define PMD_CACHE_NUM 0 | 13 | #define PMD_CACHE_NUM 1 |
14 | #define PGD_CACHE_NUM 1 | 14 | #define PGD_CACHE_NUM 2 |
15 | #else | 15 | #else |
16 | #define PTE_CACHE_NUM 0 | 16 | #define PTE_CACHE_NUM 0 |
17 | #define PMD_CACHE_NUM 1 | 17 | #define PMD_CACHE_NUM 1 |
diff --git a/include/asm-ppc64/prom.h b/include/asm-ppc64/prom.h index 76bb0266d67c..ddfe186589fa 100644 --- a/include/asm-ppc64/prom.h +++ b/include/asm-ppc64/prom.h | |||
@@ -204,6 +204,8 @@ extern void of_detach_node(const struct device_node *); | |||
204 | extern unsigned long prom_init(unsigned long, unsigned long, unsigned long, | 204 | extern unsigned long prom_init(unsigned long, unsigned long, unsigned long, |
205 | unsigned long, unsigned long); | 205 | unsigned long, unsigned long); |
206 | extern void finish_device_tree(void); | 206 | extern void finish_device_tree(void); |
207 | extern void unflatten_device_tree(void); | ||
208 | extern void early_init_devtree(void *); | ||
207 | extern int device_is_compatible(struct device_node *device, const char *); | 209 | extern int device_is_compatible(struct device_node *device, const char *); |
208 | extern int machine_is_compatible(const char *compat); | 210 | extern int machine_is_compatible(const char *compat); |
209 | extern unsigned char *get_property(struct device_node *node, const char *name, | 211 | extern unsigned char *get_property(struct device_node *node, const char *name, |
diff --git a/include/asm-ppc64/signal.h b/include/asm-ppc64/signal.h deleted file mode 100644 index 432df7dd355d..000000000000 --- a/include/asm-ppc64/signal.h +++ /dev/null | |||
@@ -1,132 +0,0 @@ | |||
1 | #ifndef _ASMPPC64_SIGNAL_H | ||
2 | #define _ASMPPC64_SIGNAL_H | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | #include <linux/compiler.h> | ||
6 | #include <asm/siginfo.h> | ||
7 | |||
8 | /* Avoid too many header ordering problems. */ | ||
9 | struct siginfo; | ||
10 | |||
11 | #define _NSIG 64 | ||
12 | #define _NSIG_BPW 64 | ||
13 | #define _NSIG_WORDS (_NSIG / _NSIG_BPW) | ||
14 | |||
15 | typedef unsigned long old_sigset_t; /* at least 32 bits */ | ||
16 | |||
17 | typedef struct { | ||
18 | unsigned long sig[_NSIG_WORDS]; | ||
19 | } sigset_t; | ||
20 | |||
21 | #define SIGHUP 1 | ||
22 | #define SIGINT 2 | ||
23 | #define SIGQUIT 3 | ||
24 | #define SIGILL 4 | ||
25 | #define SIGTRAP 5 | ||
26 | #define SIGABRT 6 | ||
27 | #define SIGIOT 6 | ||
28 | #define SIGBUS 7 | ||
29 | #define SIGFPE 8 | ||
30 | #define SIGKILL 9 | ||
31 | #define SIGUSR1 10 | ||
32 | #define SIGSEGV 11 | ||
33 | #define SIGUSR2 12 | ||
34 | #define SIGPIPE 13 | ||
35 | #define SIGALRM 14 | ||
36 | #define SIGTERM 15 | ||
37 | #define SIGSTKFLT 16 | ||
38 | #define SIGCHLD 17 | ||
39 | #define SIGCONT 18 | ||
40 | #define SIGSTOP 19 | ||
41 | #define SIGTSTP 20 | ||
42 | #define SIGTTIN 21 | ||
43 | #define SIGTTOU 22 | ||
44 | #define SIGURG 23 | ||
45 | #define SIGXCPU 24 | ||
46 | #define SIGXFSZ 25 | ||
47 | #define SIGVTALRM 26 | ||
48 | #define SIGPROF 27 | ||
49 | #define SIGWINCH 28 | ||
50 | #define SIGIO 29 | ||
51 | #define SIGPOLL SIGIO | ||
52 | /* | ||
53 | #define SIGLOST 29 | ||
54 | */ | ||
55 | #define SIGPWR 30 | ||
56 | #define SIGSYS 31 | ||
57 | #define SIGUNUSED 31 | ||
58 | |||
59 | /* These should not be considered constants from userland. */ | ||
60 | #define SIGRTMIN 32 | ||
61 | #define SIGRTMAX _NSIG | ||
62 | |||
63 | /* | ||
64 | * SA_FLAGS values: | ||
65 | * | ||
66 | * SA_ONSTACK is not currently supported, but will allow sigaltstack(2). | ||
67 | * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the | ||
68 | * SA_RESTART flag to get restarting signals (which were the default long ago) | ||
69 | * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. | ||
70 | * SA_RESETHAND clears the handler when the signal is delivered. | ||
71 | * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. | ||
72 | * SA_NODEFER prevents the current signal from being masked in the handler. | ||
73 | * | ||
74 | * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single | ||
75 | * Unix names RESETHAND and NODEFER respectively. | ||
76 | */ | ||
77 | #define SA_NOCLDSTOP 0x00000001u | ||
78 | #define SA_NOCLDWAIT 0x00000002u | ||
79 | #define SA_SIGINFO 0x00000004u | ||
80 | #define SA_ONSTACK 0x08000000u | ||
81 | #define SA_RESTART 0x10000000u | ||
82 | #define SA_NODEFER 0x40000000u | ||
83 | #define SA_RESETHAND 0x80000000u | ||
84 | |||
85 | #define SA_NOMASK SA_NODEFER | ||
86 | #define SA_ONESHOT SA_RESETHAND | ||
87 | #define SA_INTERRUPT 0x20000000u /* dummy -- ignored */ | ||
88 | |||
89 | #define SA_RESTORER 0x04000000u | ||
90 | |||
91 | /* | ||
92 | * sigaltstack controls | ||
93 | */ | ||
94 | #define SS_ONSTACK 1 | ||
95 | #define SS_DISABLE 2 | ||
96 | |||
97 | #define MINSIGSTKSZ 2048 | ||
98 | #define SIGSTKSZ 8192 | ||
99 | |||
100 | #include <asm-generic/signal.h> | ||
101 | |||
102 | struct old_sigaction { | ||
103 | __sighandler_t sa_handler; | ||
104 | old_sigset_t sa_mask; | ||
105 | unsigned long sa_flags; | ||
106 | __sigrestore_t sa_restorer; | ||
107 | }; | ||
108 | |||
109 | struct sigaction { | ||
110 | __sighandler_t sa_handler; | ||
111 | unsigned long sa_flags; | ||
112 | __sigrestore_t sa_restorer; | ||
113 | sigset_t sa_mask; /* mask last for extensibility */ | ||
114 | }; | ||
115 | |||
116 | struct k_sigaction { | ||
117 | struct sigaction sa; | ||
118 | }; | ||
119 | |||
120 | typedef struct sigaltstack { | ||
121 | void __user *ss_sp; | ||
122 | int ss_flags; | ||
123 | size_t ss_size; | ||
124 | } stack_t; | ||
125 | |||
126 | struct pt_regs; | ||
127 | struct timespec; | ||
128 | extern int do_signal(sigset_t *oldset, struct pt_regs *regs); | ||
129 | extern int do_signal32(sigset_t *oldset, struct pt_regs *regs); | ||
130 | #define ptrace_signal_deliver(regs, cookie) do { } while (0) | ||
131 | |||
132 | #endif /* _ASMPPC64_SIGNAL_H */ | ||
diff --git a/include/asm-ppc64/system.h b/include/asm-ppc64/system.h index 0cdd66c9f4b7..bf9a6aba19c9 100644 --- a/include/asm-ppc64/system.h +++ b/include/asm-ppc64/system.h | |||
@@ -149,6 +149,8 @@ struct thread_struct; | |||
149 | extern struct task_struct * _switch(struct thread_struct *prev, | 149 | extern struct task_struct * _switch(struct thread_struct *prev, |
150 | struct thread_struct *next); | 150 | struct thread_struct *next); |
151 | 151 | ||
152 | extern unsigned long klimit; | ||
153 | |||
152 | extern int powersave_nap; /* set if nap mode can be used in idle loop */ | 154 | extern int powersave_nap; /* set if nap mode can be used in idle loop */ |
153 | 155 | ||
154 | /* | 156 | /* |
diff --git a/include/asm-sh/ide.h b/include/asm-sh/ide.h index f42cf3977a57..711dad4cb48b 100644 --- a/include/asm-sh/ide.h +++ b/include/asm-sh/ide.h | |||
@@ -16,10 +16,6 @@ | |||
16 | 16 | ||
17 | #include <linux/config.h> | 17 | #include <linux/config.h> |
18 | 18 | ||
19 | #ifndef MAX_HWIFS | ||
20 | #define MAX_HWIFS CONFIG_IDE_MAX_HWIFS | ||
21 | #endif | ||
22 | |||
23 | #define ide_default_io_ctl(base) (0) | 19 | #define ide_default_io_ctl(base) (0) |
24 | 20 | ||
25 | #include <asm-generic/ide_iops.h> | 21 | #include <asm-generic/ide_iops.h> |
diff --git a/include/asm-sh64/ide.h b/include/asm-sh64/ide.h index 6fd514daa1ba..852f50afe39c 100644 --- a/include/asm-sh64/ide.h +++ b/include/asm-sh64/ide.h | |||
@@ -17,10 +17,6 @@ | |||
17 | 17 | ||
18 | #include <linux/config.h> | 18 | #include <linux/config.h> |
19 | 19 | ||
20 | #ifndef MAX_HWIFS | ||
21 | #define MAX_HWIFS CONFIG_IDE_MAX_HWIFS | ||
22 | #endif | ||
23 | |||
24 | /* Without this, the initialisation of PCI IDE cards end up calling | 20 | /* Without this, the initialisation of PCI IDE cards end up calling |
25 | * ide_init_hwif_ports, which won't work. */ | 21 | * ide_init_hwif_ports, which won't work. */ |
26 | #ifdef CONFIG_BLK_DEV_IDEPCI | 22 | #ifdef CONFIG_BLK_DEV_IDEPCI |
diff --git a/include/linux/genetlink.h b/include/linux/genetlink.h new file mode 100644 index 000000000000..84f12a41dc01 --- /dev/null +++ b/include/linux/genetlink.h | |||
@@ -0,0 +1,51 @@ | |||
1 | #ifndef __LINUX_GENERIC_NETLINK_H | ||
2 | #define __LINUX_GENERIC_NETLINK_H | ||
3 | |||
4 | #include <linux/netlink.h> | ||
5 | |||
6 | #define GENL_NAMSIZ 16 /* length of family name */ | ||
7 | |||
8 | #define GENL_MIN_ID NLMSG_MIN_TYPE | ||
9 | #define GENL_MAX_ID 1023 | ||
10 | |||
11 | struct genlmsghdr { | ||
12 | __u8 cmd; | ||
13 | __u8 version; | ||
14 | __u16 reserved; | ||
15 | }; | ||
16 | |||
17 | #define GENL_HDRLEN NLMSG_ALIGN(sizeof(struct genlmsghdr)) | ||
18 | |||
19 | /* | ||
20 | * List of reserved static generic netlink identifiers: | ||
21 | */ | ||
22 | #define GENL_ID_GENERATE 0 | ||
23 | #define GENL_ID_CTRL NLMSG_MIN_TYPE | ||
24 | |||
25 | /************************************************************************** | ||
26 | * Controller | ||
27 | **************************************************************************/ | ||
28 | |||
29 | enum { | ||
30 | CTRL_CMD_UNSPEC, | ||
31 | CTRL_CMD_NEWFAMILY, | ||
32 | CTRL_CMD_DELFAMILY, | ||
33 | CTRL_CMD_GETFAMILY, | ||
34 | CTRL_CMD_NEWOPS, | ||
35 | CTRL_CMD_DELOPS, | ||
36 | CTRL_CMD_GETOPS, | ||
37 | __CTRL_CMD_MAX, | ||
38 | }; | ||
39 | |||
40 | #define CTRL_CMD_MAX (__CTRL_CMD_MAX - 1) | ||
41 | |||
42 | enum { | ||
43 | CTRL_ATTR_UNSPEC, | ||
44 | CTRL_ATTR_FAMILY_ID, | ||
45 | CTRL_ATTR_FAMILY_NAME, | ||
46 | __CTRL_ATTR_MAX, | ||
47 | }; | ||
48 | |||
49 | #define CTRL_ATTR_MAX (__CTRL_ATTR_MAX - 1) | ||
50 | |||
51 | #endif /* __LINUX_GENERIC_NETLINK_H */ | ||
diff --git a/include/linux/ide.h b/include/linux/ide.h index 3461abc1e854..77ae55d4c13c 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h | |||
@@ -230,6 +230,7 @@ typedef struct hw_regs_s { | |||
230 | int dma; /* our dma entry */ | 230 | int dma; /* our dma entry */ |
231 | ide_ack_intr_t *ack_intr; /* acknowledge interrupt */ | 231 | ide_ack_intr_t *ack_intr; /* acknowledge interrupt */ |
232 | hwif_chipset_t chipset; | 232 | hwif_chipset_t chipset; |
233 | struct device *dev; | ||
233 | } hw_regs_t; | 234 | } hw_regs_t; |
234 | 235 | ||
235 | /* | 236 | /* |
@@ -266,6 +267,10 @@ static inline void ide_std_init_ports(hw_regs_t *hw, | |||
266 | 267 | ||
267 | #include <asm/ide.h> | 268 | #include <asm/ide.h> |
268 | 269 | ||
270 | #ifndef MAX_HWIFS | ||
271 | #define MAX_HWIFS CONFIG_IDE_MAX_HWIFS | ||
272 | #endif | ||
273 | |||
269 | /* needed on alpha, x86/x86_64, ia64, mips, ppc32 and sh */ | 274 | /* needed on alpha, x86/x86_64, ia64, mips, ppc32 and sh */ |
270 | #ifndef IDE_ARCH_OBSOLETE_DEFAULTS | 275 | #ifndef IDE_ARCH_OBSOLETE_DEFAULTS |
271 | # define ide_default_io_base(index) (0) | 276 | # define ide_default_io_base(index) (0) |
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index d21c305c6c64..fe26d431de87 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h | |||
@@ -21,6 +21,8 @@ | |||
21 | #ifndef _LINUX_IF_ETHER_H | 21 | #ifndef _LINUX_IF_ETHER_H |
22 | #define _LINUX_IF_ETHER_H | 22 | #define _LINUX_IF_ETHER_H |
23 | 23 | ||
24 | #include <linux/types.h> | ||
25 | |||
24 | /* | 26 | /* |
25 | * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble | 27 | * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble |
26 | * and FCS/CRC (frame check sequence). | 28 | * and FCS/CRC (frame check sequence). |
@@ -100,7 +102,7 @@ | |||
100 | struct ethhdr { | 102 | struct ethhdr { |
101 | unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ | 103 | unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ |
102 | unsigned char h_source[ETH_ALEN]; /* source ether addr */ | 104 | unsigned char h_source[ETH_ALEN]; /* source ether addr */ |
103 | unsigned short h_proto; /* packet type ID field */ | 105 | __be16 h_proto; /* packet type ID field */ |
104 | } __attribute__((packed)); | 106 | } __attribute__((packed)); |
105 | 107 | ||
106 | #ifdef __KERNEL__ | 108 | #ifdef __KERNEL__ |
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index c6efce4a04a4..936f8b76114e 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -927,6 +927,13 @@ extern int netdev_max_backlog; | |||
927 | extern int weight_p; | 927 | extern int weight_p; |
928 | extern int netdev_set_master(struct net_device *dev, struct net_device *master); | 928 | extern int netdev_set_master(struct net_device *dev, struct net_device *master); |
929 | extern int skb_checksum_help(struct sk_buff *skb, int inward); | 929 | extern int skb_checksum_help(struct sk_buff *skb, int inward); |
930 | #ifdef CONFIG_BUG | ||
931 | extern void netdev_rx_csum_fault(struct net_device *dev); | ||
932 | #else | ||
933 | static inline void netdev_rx_csum_fault(struct net_device *dev) | ||
934 | { | ||
935 | } | ||
936 | #endif | ||
930 | /* rx skb timestamps */ | 937 | /* rx skb timestamps */ |
931 | extern void net_enable_timestamp(void); | 938 | extern void net_enable_timestamp(void); |
932 | extern void net_disable_timestamp(void); | 939 | extern void net_disable_timestamp(void); |
diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h new file mode 100644 index 000000000000..6d39b518486b --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_common.h | |||
@@ -0,0 +1,159 @@ | |||
1 | #ifndef _NF_CONNTRACK_COMMON_H | ||
2 | #define _NF_CONNTRACK_COMMON_H | ||
3 | /* Connection state tracking for netfilter. This is separated from, | ||
4 | but required by, the NAT layer; it can also be used by an iptables | ||
5 | extension. */ | ||
6 | enum ip_conntrack_info | ||
7 | { | ||
8 | /* Part of an established connection (either direction). */ | ||
9 | IP_CT_ESTABLISHED, | ||
10 | |||
11 | /* Like NEW, but related to an existing connection, or ICMP error | ||
12 | (in either direction). */ | ||
13 | IP_CT_RELATED, | ||
14 | |||
15 | /* Started a new connection to track (only | ||
16 | IP_CT_DIR_ORIGINAL); may be a retransmission. */ | ||
17 | IP_CT_NEW, | ||
18 | |||
19 | /* >= this indicates reply direction */ | ||
20 | IP_CT_IS_REPLY, | ||
21 | |||
22 | /* Number of distinct IP_CT types (no NEW in reply dirn). */ | ||
23 | IP_CT_NUMBER = IP_CT_IS_REPLY * 2 - 1 | ||
24 | }; | ||
25 | |||
26 | /* Bitset representing status of connection. */ | ||
27 | enum ip_conntrack_status { | ||
28 | /* It's an expected connection: bit 0 set. This bit never changed */ | ||
29 | IPS_EXPECTED_BIT = 0, | ||
30 | IPS_EXPECTED = (1 << IPS_EXPECTED_BIT), | ||
31 | |||
32 | /* We've seen packets both ways: bit 1 set. Can be set, not unset. */ | ||
33 | IPS_SEEN_REPLY_BIT = 1, | ||
34 | IPS_SEEN_REPLY = (1 << IPS_SEEN_REPLY_BIT), | ||
35 | |||
36 | /* Conntrack should never be early-expired. */ | ||
37 | IPS_ASSURED_BIT = 2, | ||
38 | IPS_ASSURED = (1 << IPS_ASSURED_BIT), | ||
39 | |||
40 | /* Connection is confirmed: originating packet has left box */ | ||
41 | IPS_CONFIRMED_BIT = 3, | ||
42 | IPS_CONFIRMED = (1 << IPS_CONFIRMED_BIT), | ||
43 | |||
44 | /* Connection needs src nat in orig dir. This bit never changed. */ | ||
45 | IPS_SRC_NAT_BIT = 4, | ||
46 | IPS_SRC_NAT = (1 << IPS_SRC_NAT_BIT), | ||
47 | |||
48 | /* Connection needs dst nat in orig dir. This bit never changed. */ | ||
49 | IPS_DST_NAT_BIT = 5, | ||
50 | IPS_DST_NAT = (1 << IPS_DST_NAT_BIT), | ||
51 | |||
52 | /* Both together. */ | ||
53 | IPS_NAT_MASK = (IPS_DST_NAT | IPS_SRC_NAT), | ||
54 | |||
55 | /* Connection needs TCP sequence adjusted. */ | ||
56 | IPS_SEQ_ADJUST_BIT = 6, | ||
57 | IPS_SEQ_ADJUST = (1 << IPS_SEQ_ADJUST_BIT), | ||
58 | |||
59 | /* NAT initialization bits. */ | ||
60 | IPS_SRC_NAT_DONE_BIT = 7, | ||
61 | IPS_SRC_NAT_DONE = (1 << IPS_SRC_NAT_DONE_BIT), | ||
62 | |||
63 | IPS_DST_NAT_DONE_BIT = 8, | ||
64 | IPS_DST_NAT_DONE = (1 << IPS_DST_NAT_DONE_BIT), | ||
65 | |||
66 | /* Both together */ | ||
67 | IPS_NAT_DONE_MASK = (IPS_DST_NAT_DONE | IPS_SRC_NAT_DONE), | ||
68 | |||
69 | /* Connection is dying (removed from lists), can not be unset. */ | ||
70 | IPS_DYING_BIT = 9, | ||
71 | IPS_DYING = (1 << IPS_DYING_BIT), | ||
72 | }; | ||
73 | |||
74 | /* Connection tracking event bits */ | ||
75 | enum ip_conntrack_events | ||
76 | { | ||
77 | /* New conntrack */ | ||
78 | IPCT_NEW_BIT = 0, | ||
79 | IPCT_NEW = (1 << IPCT_NEW_BIT), | ||
80 | |||
81 | /* Expected connection */ | ||
82 | IPCT_RELATED_BIT = 1, | ||
83 | IPCT_RELATED = (1 << IPCT_RELATED_BIT), | ||
84 | |||
85 | /* Destroyed conntrack */ | ||
86 | IPCT_DESTROY_BIT = 2, | ||
87 | IPCT_DESTROY = (1 << IPCT_DESTROY_BIT), | ||
88 | |||
89 | /* Timer has been refreshed */ | ||
90 | IPCT_REFRESH_BIT = 3, | ||
91 | IPCT_REFRESH = (1 << IPCT_REFRESH_BIT), | ||
92 | |||
93 | /* Status has changed */ | ||
94 | IPCT_STATUS_BIT = 4, | ||
95 | IPCT_STATUS = (1 << IPCT_STATUS_BIT), | ||
96 | |||
97 | /* Update of protocol info */ | ||
98 | IPCT_PROTOINFO_BIT = 5, | ||
99 | IPCT_PROTOINFO = (1 << IPCT_PROTOINFO_BIT), | ||
100 | |||
101 | /* Volatile protocol info */ | ||
102 | IPCT_PROTOINFO_VOLATILE_BIT = 6, | ||
103 | IPCT_PROTOINFO_VOLATILE = (1 << IPCT_PROTOINFO_VOLATILE_BIT), | ||
104 | |||
105 | /* New helper for conntrack */ | ||
106 | IPCT_HELPER_BIT = 7, | ||
107 | IPCT_HELPER = (1 << IPCT_HELPER_BIT), | ||
108 | |||
109 | /* Update of helper info */ | ||
110 | IPCT_HELPINFO_BIT = 8, | ||
111 | IPCT_HELPINFO = (1 << IPCT_HELPINFO_BIT), | ||
112 | |||
113 | /* Volatile helper info */ | ||
114 | IPCT_HELPINFO_VOLATILE_BIT = 9, | ||
115 | IPCT_HELPINFO_VOLATILE = (1 << IPCT_HELPINFO_VOLATILE_BIT), | ||
116 | |||
117 | /* NAT info */ | ||
118 | IPCT_NATINFO_BIT = 10, | ||
119 | IPCT_NATINFO = (1 << IPCT_NATINFO_BIT), | ||
120 | |||
121 | /* Counter highest bit has been set */ | ||
122 | IPCT_COUNTER_FILLING_BIT = 11, | ||
123 | IPCT_COUNTER_FILLING = (1 << IPCT_COUNTER_FILLING_BIT), | ||
124 | }; | ||
125 | |||
126 | enum ip_conntrack_expect_events { | ||
127 | IPEXP_NEW_BIT = 0, | ||
128 | IPEXP_NEW = (1 << IPEXP_NEW_BIT), | ||
129 | }; | ||
130 | |||
131 | #ifdef __KERNEL__ | ||
132 | struct ip_conntrack_counter | ||
133 | { | ||
134 | u_int32_t packets; | ||
135 | u_int32_t bytes; | ||
136 | }; | ||
137 | |||
138 | struct ip_conntrack_stat | ||
139 | { | ||
140 | unsigned int searched; | ||
141 | unsigned int found; | ||
142 | unsigned int new; | ||
143 | unsigned int invalid; | ||
144 | unsigned int ignore; | ||
145 | unsigned int delete; | ||
146 | unsigned int delete_list; | ||
147 | unsigned int insert; | ||
148 | unsigned int insert_failed; | ||
149 | unsigned int drop; | ||
150 | unsigned int early_drop; | ||
151 | unsigned int error; | ||
152 | unsigned int expect_new; | ||
153 | unsigned int expect_create; | ||
154 | unsigned int expect_delete; | ||
155 | }; | ||
156 | |||
157 | #endif /* __KERNEL__ */ | ||
158 | |||
159 | #endif /* _NF_CONNTRACK_COMMON_H */ | ||
diff --git a/include/linux/netfilter/nf_conntrack_ftp.h b/include/linux/netfilter/nf_conntrack_ftp.h new file mode 100644 index 000000000000..ad4a41c9ce93 --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_ftp.h | |||
@@ -0,0 +1,44 @@ | |||
1 | #ifndef _NF_CONNTRACK_FTP_H | ||
2 | #define _NF_CONNTRACK_FTP_H | ||
3 | /* FTP tracking. */ | ||
4 | |||
5 | /* This enum is exposed to userspace */ | ||
6 | enum ip_ct_ftp_type | ||
7 | { | ||
8 | /* PORT command from client */ | ||
9 | IP_CT_FTP_PORT, | ||
10 | /* PASV response from server */ | ||
11 | IP_CT_FTP_PASV, | ||
12 | /* EPRT command from client */ | ||
13 | IP_CT_FTP_EPRT, | ||
14 | /* EPSV response from server */ | ||
15 | IP_CT_FTP_EPSV, | ||
16 | }; | ||
17 | |||
18 | #ifdef __KERNEL__ | ||
19 | |||
20 | #define FTP_PORT 21 | ||
21 | |||
22 | #define NUM_SEQ_TO_REMEMBER 2 | ||
23 | /* This structure exists only once per master */ | ||
24 | struct ip_ct_ftp_master { | ||
25 | /* Valid seq positions for cmd matching after newline */ | ||
26 | u_int32_t seq_aft_nl[IP_CT_DIR_MAX][NUM_SEQ_TO_REMEMBER]; | ||
27 | /* 0 means seq_match_aft_nl not set */ | ||
28 | int seq_aft_nl_num[IP_CT_DIR_MAX]; | ||
29 | }; | ||
30 | |||
31 | struct ip_conntrack_expect; | ||
32 | |||
33 | /* For NAT to hook in when we find a packet which describes what other | ||
34 | * connection we should expect. */ | ||
35 | extern unsigned int (*ip_nat_ftp_hook)(struct sk_buff **pskb, | ||
36 | enum ip_conntrack_info ctinfo, | ||
37 | enum ip_ct_ftp_type type, | ||
38 | unsigned int matchoff, | ||
39 | unsigned int matchlen, | ||
40 | struct ip_conntrack_expect *exp, | ||
41 | u32 *seq); | ||
42 | #endif /* __KERNEL__ */ | ||
43 | |||
44 | #endif /* _NF_CONNTRACK_FTP_H */ | ||
diff --git a/include/linux/netfilter/nf_conntrack_sctp.h b/include/linux/netfilter/nf_conntrack_sctp.h new file mode 100644 index 000000000000..b8994d9fd1a9 --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_sctp.h | |||
@@ -0,0 +1,27 @@ | |||
1 | #ifndef _NF_CONNTRACK_SCTP_H | ||
2 | #define _NF_CONNTRACK_SCTP_H | ||
3 | /* SCTP tracking. */ | ||
4 | |||
5 | #include <linux/netfilter/nf_conntrack_tuple_common.h> | ||
6 | |||
7 | enum sctp_conntrack { | ||
8 | SCTP_CONNTRACK_NONE, | ||
9 | SCTP_CONNTRACK_CLOSED, | ||
10 | SCTP_CONNTRACK_COOKIE_WAIT, | ||
11 | SCTP_CONNTRACK_COOKIE_ECHOED, | ||
12 | SCTP_CONNTRACK_ESTABLISHED, | ||
13 | SCTP_CONNTRACK_SHUTDOWN_SENT, | ||
14 | SCTP_CONNTRACK_SHUTDOWN_RECD, | ||
15 | SCTP_CONNTRACK_SHUTDOWN_ACK_SENT, | ||
16 | SCTP_CONNTRACK_MAX | ||
17 | }; | ||
18 | |||
19 | struct ip_ct_sctp | ||
20 | { | ||
21 | enum sctp_conntrack state; | ||
22 | |||
23 | u_int32_t vtag[IP_CT_DIR_MAX]; | ||
24 | u_int32_t ttag[IP_CT_DIR_MAX]; | ||
25 | }; | ||
26 | |||
27 | #endif /* _NF_CONNTRACK_SCTP_H */ | ||
diff --git a/include/linux/netfilter/nf_conntrack_tcp.h b/include/linux/netfilter/nf_conntrack_tcp.h new file mode 100644 index 000000000000..b2feeffde384 --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_tcp.h | |||
@@ -0,0 +1,56 @@ | |||
1 | #ifndef _NF_CONNTRACK_TCP_H | ||
2 | #define _NF_CONNTRACK_TCP_H | ||
3 | /* TCP tracking. */ | ||
4 | |||
5 | /* This is exposed to userspace (ctnetlink) */ | ||
6 | enum tcp_conntrack { | ||
7 | TCP_CONNTRACK_NONE, | ||
8 | TCP_CONNTRACK_SYN_SENT, | ||
9 | TCP_CONNTRACK_SYN_RECV, | ||
10 | TCP_CONNTRACK_ESTABLISHED, | ||
11 | TCP_CONNTRACK_FIN_WAIT, | ||
12 | TCP_CONNTRACK_CLOSE_WAIT, | ||
13 | TCP_CONNTRACK_LAST_ACK, | ||
14 | TCP_CONNTRACK_TIME_WAIT, | ||
15 | TCP_CONNTRACK_CLOSE, | ||
16 | TCP_CONNTRACK_LISTEN, | ||
17 | TCP_CONNTRACK_MAX, | ||
18 | TCP_CONNTRACK_IGNORE | ||
19 | }; | ||
20 | |||
21 | /* Window scaling is advertised by the sender */ | ||
22 | #define IP_CT_TCP_FLAG_WINDOW_SCALE 0x01 | ||
23 | |||
24 | /* SACK is permitted by the sender */ | ||
25 | #define IP_CT_TCP_FLAG_SACK_PERM 0x02 | ||
26 | |||
27 | /* This sender sent FIN first */ | ||
28 | #define IP_CT_TCP_FLAG_CLOSE_INIT 0x03 | ||
29 | |||
30 | #ifdef __KERNEL__ | ||
31 | |||
32 | struct ip_ct_tcp_state { | ||
33 | u_int32_t td_end; /* max of seq + len */ | ||
34 | u_int32_t td_maxend; /* max of ack + max(win, 1) */ | ||
35 | u_int32_t td_maxwin; /* max(win) */ | ||
36 | u_int8_t td_scale; /* window scale factor */ | ||
37 | u_int8_t loose; /* used when connection picked up from the middle */ | ||
38 | u_int8_t flags; /* per direction options */ | ||
39 | }; | ||
40 | |||
41 | struct ip_ct_tcp | ||
42 | { | ||
43 | struct ip_ct_tcp_state seen[2]; /* connection parameters per direction */ | ||
44 | u_int8_t state; /* state of the connection (enum tcp_conntrack) */ | ||
45 | /* For detecting stale connections */ | ||
46 | u_int8_t last_dir; /* Direction of the last packet (enum ip_conntrack_dir) */ | ||
47 | u_int8_t retrans; /* Number of retransmitted packets */ | ||
48 | u_int8_t last_index; /* Index of the last packet */ | ||
49 | u_int32_t last_seq; /* Last sequence number seen in dir */ | ||
50 | u_int32_t last_ack; /* Last sequence number seen in opposite dir */ | ||
51 | u_int32_t last_end; /* Last seq + len */ | ||
52 | }; | ||
53 | |||
54 | #endif /* __KERNEL__ */ | ||
55 | |||
56 | #endif /* _NF_CONNTRACK_TCP_H */ | ||
diff --git a/include/linux/netfilter/nf_conntrack_tuple_common.h b/include/linux/netfilter/nf_conntrack_tuple_common.h new file mode 100644 index 000000000000..8e145f0d61cb --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_tuple_common.h | |||
@@ -0,0 +1,13 @@ | |||
1 | #ifndef _NF_CONNTRACK_TUPLE_COMMON_H | ||
2 | #define _NF_CONNTRACK_TUPLE_COMMON_H | ||
3 | |||
4 | enum ip_conntrack_dir | ||
5 | { | ||
6 | IP_CT_DIR_ORIGINAL, | ||
7 | IP_CT_DIR_REPLY, | ||
8 | IP_CT_DIR_MAX | ||
9 | }; | ||
10 | |||
11 | #define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL) | ||
12 | |||
13 | #endif /* _NF_CONNTRACK_TUPLE_COMMON_H */ | ||
diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h index d078bb91d9e5..b3432ab59a17 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack.h +++ b/include/linux/netfilter_ipv4/ip_conntrack.h | |||
@@ -1,132 +1,7 @@ | |||
1 | #ifndef _IP_CONNTRACK_H | 1 | #ifndef _IP_CONNTRACK_H |
2 | #define _IP_CONNTRACK_H | 2 | #define _IP_CONNTRACK_H |
3 | /* Connection state tracking for netfilter. This is separated from, | ||
4 | but required by, the NAT layer; it can also be used by an iptables | ||
5 | extension. */ | ||
6 | enum ip_conntrack_info | ||
7 | { | ||
8 | /* Part of an established connection (either direction). */ | ||
9 | IP_CT_ESTABLISHED, | ||
10 | |||
11 | /* Like NEW, but related to an existing connection, or ICMP error | ||
12 | (in either direction). */ | ||
13 | IP_CT_RELATED, | ||
14 | |||
15 | /* Started a new connection to track (only | ||
16 | IP_CT_DIR_ORIGINAL); may be a retransmission. */ | ||
17 | IP_CT_NEW, | ||
18 | |||
19 | /* >= this indicates reply direction */ | ||
20 | IP_CT_IS_REPLY, | ||
21 | |||
22 | /* Number of distinct IP_CT types (no NEW in reply dirn). */ | ||
23 | IP_CT_NUMBER = IP_CT_IS_REPLY * 2 - 1 | ||
24 | }; | ||
25 | |||
26 | /* Bitset representing status of connection. */ | ||
27 | enum ip_conntrack_status { | ||
28 | /* It's an expected connection: bit 0 set. This bit never changed */ | ||
29 | IPS_EXPECTED_BIT = 0, | ||
30 | IPS_EXPECTED = (1 << IPS_EXPECTED_BIT), | ||
31 | |||
32 | /* We've seen packets both ways: bit 1 set. Can be set, not unset. */ | ||
33 | IPS_SEEN_REPLY_BIT = 1, | ||
34 | IPS_SEEN_REPLY = (1 << IPS_SEEN_REPLY_BIT), | ||
35 | |||
36 | /* Conntrack should never be early-expired. */ | ||
37 | IPS_ASSURED_BIT = 2, | ||
38 | IPS_ASSURED = (1 << IPS_ASSURED_BIT), | ||
39 | |||
40 | /* Connection is confirmed: originating packet has left box */ | ||
41 | IPS_CONFIRMED_BIT = 3, | ||
42 | IPS_CONFIRMED = (1 << IPS_CONFIRMED_BIT), | ||
43 | |||
44 | /* Connection needs src nat in orig dir. This bit never changed. */ | ||
45 | IPS_SRC_NAT_BIT = 4, | ||
46 | IPS_SRC_NAT = (1 << IPS_SRC_NAT_BIT), | ||
47 | |||
48 | /* Connection needs dst nat in orig dir. This bit never changed. */ | ||
49 | IPS_DST_NAT_BIT = 5, | ||
50 | IPS_DST_NAT = (1 << IPS_DST_NAT_BIT), | ||
51 | |||
52 | /* Both together. */ | ||
53 | IPS_NAT_MASK = (IPS_DST_NAT | IPS_SRC_NAT), | ||
54 | |||
55 | /* Connection needs TCP sequence adjusted. */ | ||
56 | IPS_SEQ_ADJUST_BIT = 6, | ||
57 | IPS_SEQ_ADJUST = (1 << IPS_SEQ_ADJUST_BIT), | ||
58 | |||
59 | /* NAT initialization bits. */ | ||
60 | IPS_SRC_NAT_DONE_BIT = 7, | ||
61 | IPS_SRC_NAT_DONE = (1 << IPS_SRC_NAT_DONE_BIT), | ||
62 | |||
63 | IPS_DST_NAT_DONE_BIT = 8, | ||
64 | IPS_DST_NAT_DONE = (1 << IPS_DST_NAT_DONE_BIT), | ||
65 | |||
66 | /* Both together */ | ||
67 | IPS_NAT_DONE_MASK = (IPS_DST_NAT_DONE | IPS_SRC_NAT_DONE), | ||
68 | |||
69 | /* Connection is dying (removed from lists), can not be unset. */ | ||
70 | IPS_DYING_BIT = 9, | ||
71 | IPS_DYING = (1 << IPS_DYING_BIT), | ||
72 | }; | ||
73 | |||
74 | /* Connection tracking event bits */ | ||
75 | enum ip_conntrack_events | ||
76 | { | ||
77 | /* New conntrack */ | ||
78 | IPCT_NEW_BIT = 0, | ||
79 | IPCT_NEW = (1 << IPCT_NEW_BIT), | ||
80 | |||
81 | /* Expected connection */ | ||
82 | IPCT_RELATED_BIT = 1, | ||
83 | IPCT_RELATED = (1 << IPCT_RELATED_BIT), | ||
84 | |||
85 | /* Destroyed conntrack */ | ||
86 | IPCT_DESTROY_BIT = 2, | ||
87 | IPCT_DESTROY = (1 << IPCT_DESTROY_BIT), | ||
88 | |||
89 | /* Timer has been refreshed */ | ||
90 | IPCT_REFRESH_BIT = 3, | ||
91 | IPCT_REFRESH = (1 << IPCT_REFRESH_BIT), | ||
92 | |||
93 | /* Status has changed */ | ||
94 | IPCT_STATUS_BIT = 4, | ||
95 | IPCT_STATUS = (1 << IPCT_STATUS_BIT), | ||
96 | |||
97 | /* Update of protocol info */ | ||
98 | IPCT_PROTOINFO_BIT = 5, | ||
99 | IPCT_PROTOINFO = (1 << IPCT_PROTOINFO_BIT), | ||
100 | |||
101 | /* Volatile protocol info */ | ||
102 | IPCT_PROTOINFO_VOLATILE_BIT = 6, | ||
103 | IPCT_PROTOINFO_VOLATILE = (1 << IPCT_PROTOINFO_VOLATILE_BIT), | ||
104 | |||
105 | /* New helper for conntrack */ | ||
106 | IPCT_HELPER_BIT = 7, | ||
107 | IPCT_HELPER = (1 << IPCT_HELPER_BIT), | ||
108 | |||
109 | /* Update of helper info */ | ||
110 | IPCT_HELPINFO_BIT = 8, | ||
111 | IPCT_HELPINFO = (1 << IPCT_HELPINFO_BIT), | ||
112 | |||
113 | /* Volatile helper info */ | ||
114 | IPCT_HELPINFO_VOLATILE_BIT = 9, | ||
115 | IPCT_HELPINFO_VOLATILE = (1 << IPCT_HELPINFO_VOLATILE_BIT), | ||
116 | 3 | ||
117 | /* NAT info */ | 4 | #include <linux/netfilter/nf_conntrack_common.h> |
118 | IPCT_NATINFO_BIT = 10, | ||
119 | IPCT_NATINFO = (1 << IPCT_NATINFO_BIT), | ||
120 | |||
121 | /* Counter highest bit has been set */ | ||
122 | IPCT_COUNTER_FILLING_BIT = 11, | ||
123 | IPCT_COUNTER_FILLING = (1 << IPCT_COUNTER_FILLING_BIT), | ||
124 | }; | ||
125 | |||
126 | enum ip_conntrack_expect_events { | ||
127 | IPEXP_NEW_BIT = 0, | ||
128 | IPEXP_NEW = (1 << IPEXP_NEW_BIT), | ||
129 | }; | ||
130 | 5 | ||
131 | #ifdef __KERNEL__ | 6 | #ifdef __KERNEL__ |
132 | #include <linux/config.h> | 7 | #include <linux/config.h> |
@@ -194,12 +69,6 @@ do { \ | |||
194 | #define IP_NF_ASSERT(x) | 69 | #define IP_NF_ASSERT(x) |
195 | #endif | 70 | #endif |
196 | 71 | ||
197 | struct ip_conntrack_counter | ||
198 | { | ||
199 | u_int32_t packets; | ||
200 | u_int32_t bytes; | ||
201 | }; | ||
202 | |||
203 | struct ip_conntrack_helper; | 72 | struct ip_conntrack_helper; |
204 | 73 | ||
205 | struct ip_conntrack | 74 | struct ip_conntrack |
@@ -426,25 +295,6 @@ static inline int is_dying(struct ip_conntrack *ct) | |||
426 | 295 | ||
427 | extern unsigned int ip_conntrack_htable_size; | 296 | extern unsigned int ip_conntrack_htable_size; |
428 | 297 | ||
429 | struct ip_conntrack_stat | ||
430 | { | ||
431 | unsigned int searched; | ||
432 | unsigned int found; | ||
433 | unsigned int new; | ||
434 | unsigned int invalid; | ||
435 | unsigned int ignore; | ||
436 | unsigned int delete; | ||
437 | unsigned int delete_list; | ||
438 | unsigned int insert; | ||
439 | unsigned int insert_failed; | ||
440 | unsigned int drop; | ||
441 | unsigned int early_drop; | ||
442 | unsigned int error; | ||
443 | unsigned int expect_new; | ||
444 | unsigned int expect_create; | ||
445 | unsigned int expect_delete; | ||
446 | }; | ||
447 | |||
448 | #define CONNTRACK_STAT_INC(count) (__get_cpu_var(ip_conntrack_stat).count++) | 298 | #define CONNTRACK_STAT_INC(count) (__get_cpu_var(ip_conntrack_stat).count++) |
449 | 299 | ||
450 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS | 300 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS |
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_ftp.h b/include/linux/netfilter_ipv4/ip_conntrack_ftp.h index 5f06429b9047..63811934de4d 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_ftp.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_ftp.h | |||
@@ -1,43 +1,6 @@ | |||
1 | #ifndef _IP_CONNTRACK_FTP_H | 1 | #ifndef _IP_CONNTRACK_FTP_H |
2 | #define _IP_CONNTRACK_FTP_H | 2 | #define _IP_CONNTRACK_FTP_H |
3 | /* FTP tracking. */ | ||
4 | 3 | ||
5 | #ifdef __KERNEL__ | 4 | #include <linux/netfilter/nf_conntrack_ftp.h> |
6 | 5 | ||
7 | #define FTP_PORT 21 | ||
8 | |||
9 | #endif /* __KERNEL__ */ | ||
10 | |||
11 | enum ip_ct_ftp_type | ||
12 | { | ||
13 | /* PORT command from client */ | ||
14 | IP_CT_FTP_PORT, | ||
15 | /* PASV response from server */ | ||
16 | IP_CT_FTP_PASV, | ||
17 | /* EPRT command from client */ | ||
18 | IP_CT_FTP_EPRT, | ||
19 | /* EPSV response from server */ | ||
20 | IP_CT_FTP_EPSV, | ||
21 | }; | ||
22 | |||
23 | #define NUM_SEQ_TO_REMEMBER 2 | ||
24 | /* This structure exists only once per master */ | ||
25 | struct ip_ct_ftp_master { | ||
26 | /* Valid seq positions for cmd matching after newline */ | ||
27 | u_int32_t seq_aft_nl[IP_CT_DIR_MAX][NUM_SEQ_TO_REMEMBER]; | ||
28 | /* 0 means seq_match_aft_nl not set */ | ||
29 | int seq_aft_nl_num[IP_CT_DIR_MAX]; | ||
30 | }; | ||
31 | |||
32 | struct ip_conntrack_expect; | ||
33 | |||
34 | /* For NAT to hook in when we find a packet which describes what other | ||
35 | * connection we should expect. */ | ||
36 | extern unsigned int (*ip_nat_ftp_hook)(struct sk_buff **pskb, | ||
37 | enum ip_conntrack_info ctinfo, | ||
38 | enum ip_ct_ftp_type type, | ||
39 | unsigned int matchoff, | ||
40 | unsigned int matchlen, | ||
41 | struct ip_conntrack_expect *exp, | ||
42 | u32 *seq); | ||
43 | #endif /* _IP_CONNTRACK_FTP_H */ | 6 | #endif /* _IP_CONNTRACK_FTP_H */ |
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_icmp.h b/include/linux/netfilter_ipv4/ip_conntrack_icmp.h index f1664abbe392..eed5ee3e4744 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_icmp.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_icmp.h | |||
@@ -1,11 +1,6 @@ | |||
1 | #ifndef _IP_CONNTRACK_ICMP_H | 1 | #ifndef _IP_CONNTRACK_ICMP_H |
2 | #define _IP_CONNTRACK_ICMP_H | 2 | #define _IP_CONNTRACK_ICMP_H |
3 | /* ICMP tracking. */ | ||
4 | #include <asm/atomic.h> | ||
5 | 3 | ||
6 | struct ip_ct_icmp | 4 | #include <net/netfilter/ipv4/nf_conntrack_icmp.h> |
7 | { | 5 | |
8 | /* Optimization: when number in == number out, forget immediately. */ | ||
9 | atomic_t count; | ||
10 | }; | ||
11 | #endif /* _IP_CONNTRACK_ICMP_H */ | 6 | #endif /* _IP_CONNTRACK_ICMP_H */ |
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_sctp.h b/include/linux/netfilter_ipv4/ip_conntrack_sctp.h index 7a8d869321f7..4099a041a32a 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_sctp.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_sctp.h | |||
@@ -1,25 +1,6 @@ | |||
1 | #ifndef _IP_CONNTRACK_SCTP_H | 1 | #ifndef _IP_CONNTRACK_SCTP_H |
2 | #define _IP_CONNTRACK_SCTP_H | 2 | #define _IP_CONNTRACK_SCTP_H |
3 | /* SCTP tracking. */ | ||
4 | 3 | ||
5 | enum sctp_conntrack { | 4 | #include <linux/netfilter/nf_conntrack_sctp.h> |
6 | SCTP_CONNTRACK_NONE, | ||
7 | SCTP_CONNTRACK_CLOSED, | ||
8 | SCTP_CONNTRACK_COOKIE_WAIT, | ||
9 | SCTP_CONNTRACK_COOKIE_ECHOED, | ||
10 | SCTP_CONNTRACK_ESTABLISHED, | ||
11 | SCTP_CONNTRACK_SHUTDOWN_SENT, | ||
12 | SCTP_CONNTRACK_SHUTDOWN_RECD, | ||
13 | SCTP_CONNTRACK_SHUTDOWN_ACK_SENT, | ||
14 | SCTP_CONNTRACK_MAX | ||
15 | }; | ||
16 | |||
17 | struct ip_ct_sctp | ||
18 | { | ||
19 | enum sctp_conntrack state; | ||
20 | |||
21 | u_int32_t vtag[IP_CT_DIR_MAX]; | ||
22 | u_int32_t ttag[IP_CT_DIR_MAX]; | ||
23 | }; | ||
24 | 5 | ||
25 | #endif /* _IP_CONNTRACK_SCTP_H */ | 6 | #endif /* _IP_CONNTRACK_SCTP_H */ |
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_tcp.h b/include/linux/netfilter_ipv4/ip_conntrack_tcp.h index 16da044d97a7..876b8fb17e68 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_tcp.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_tcp.h | |||
@@ -1,51 +1,6 @@ | |||
1 | #ifndef _IP_CONNTRACK_TCP_H | 1 | #ifndef _IP_CONNTRACK_TCP_H |
2 | #define _IP_CONNTRACK_TCP_H | 2 | #define _IP_CONNTRACK_TCP_H |
3 | /* TCP tracking. */ | ||
4 | 3 | ||
5 | enum tcp_conntrack { | 4 | #include <linux/netfilter/nf_conntrack_tcp.h> |
6 | TCP_CONNTRACK_NONE, | ||
7 | TCP_CONNTRACK_SYN_SENT, | ||
8 | TCP_CONNTRACK_SYN_RECV, | ||
9 | TCP_CONNTRACK_ESTABLISHED, | ||
10 | TCP_CONNTRACK_FIN_WAIT, | ||
11 | TCP_CONNTRACK_CLOSE_WAIT, | ||
12 | TCP_CONNTRACK_LAST_ACK, | ||
13 | TCP_CONNTRACK_TIME_WAIT, | ||
14 | TCP_CONNTRACK_CLOSE, | ||
15 | TCP_CONNTRACK_LISTEN, | ||
16 | TCP_CONNTRACK_MAX, | ||
17 | TCP_CONNTRACK_IGNORE | ||
18 | }; | ||
19 | |||
20 | /* Window scaling is advertised by the sender */ | ||
21 | #define IP_CT_TCP_FLAG_WINDOW_SCALE 0x01 | ||
22 | |||
23 | /* SACK is permitted by the sender */ | ||
24 | #define IP_CT_TCP_FLAG_SACK_PERM 0x02 | ||
25 | |||
26 | /* This sender sent FIN first */ | ||
27 | #define IP_CT_TCP_FLAG_CLOSE_INIT 0x03 | ||
28 | |||
29 | struct ip_ct_tcp_state { | ||
30 | u_int32_t td_end; /* max of seq + len */ | ||
31 | u_int32_t td_maxend; /* max of ack + max(win, 1) */ | ||
32 | u_int32_t td_maxwin; /* max(win) */ | ||
33 | u_int8_t td_scale; /* window scale factor */ | ||
34 | u_int8_t loose; /* used when connection picked up from the middle */ | ||
35 | u_int8_t flags; /* per direction options */ | ||
36 | }; | ||
37 | |||
38 | struct ip_ct_tcp | ||
39 | { | ||
40 | struct ip_ct_tcp_state seen[2]; /* connection parameters per direction */ | ||
41 | u_int8_t state; /* state of the connection (enum tcp_conntrack) */ | ||
42 | /* For detecting stale connections */ | ||
43 | u_int8_t last_dir; /* Direction of the last packet (enum ip_conntrack_dir) */ | ||
44 | u_int8_t retrans; /* Number of retransmitted packets */ | ||
45 | u_int8_t last_index; /* Index of the last packet */ | ||
46 | u_int32_t last_seq; /* Last sequence number seen in dir */ | ||
47 | u_int32_t last_ack; /* Last sequence number seen in opposite dir */ | ||
48 | u_int32_t last_end; /* Last seq + len */ | ||
49 | }; | ||
50 | 5 | ||
51 | #endif /* _IP_CONNTRACK_TCP_H */ | 6 | #endif /* _IP_CONNTRACK_TCP_H */ |
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h b/include/linux/netfilter_ipv4/ip_conntrack_tuple.h index 3232db11a4e5..2fdabdb4c0ef 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_tuple.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define _IP_CONNTRACK_TUPLE_H | 2 | #define _IP_CONNTRACK_TUPLE_H |
3 | 3 | ||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | #include <linux/netfilter/nf_conntrack_tuple_common.h> | ||
5 | 6 | ||
6 | /* A `tuple' is a structure containing the information to uniquely | 7 | /* A `tuple' is a structure containing the information to uniquely |
7 | identify a connection. ie. if two packets have the same tuple, they | 8 | identify a connection. ie. if two packets have the same tuple, they |
@@ -88,13 +89,6 @@ struct ip_conntrack_tuple | |||
88 | (tuple)->dst.u.all = 0; \ | 89 | (tuple)->dst.u.all = 0; \ |
89 | } while (0) | 90 | } while (0) |
90 | 91 | ||
91 | enum ip_conntrack_dir | ||
92 | { | ||
93 | IP_CT_DIR_ORIGINAL, | ||
94 | IP_CT_DIR_REPLY, | ||
95 | IP_CT_DIR_MAX | ||
96 | }; | ||
97 | |||
98 | #ifdef __KERNEL__ | 92 | #ifdef __KERNEL__ |
99 | 93 | ||
100 | #define DUMP_TUPLE(tp) \ | 94 | #define DUMP_TUPLE(tp) \ |
@@ -103,8 +97,6 @@ DEBUGP("tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", \ | |||
103 | NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all), \ | 97 | NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all), \ |
104 | NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all)) | 98 | NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all)) |
105 | 99 | ||
106 | #define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL) | ||
107 | |||
108 | /* If we're the first tuple, it's the original dir. */ | 100 | /* If we're the first tuple, it's the original dir. */ |
109 | #define DIRECTION(h) ((enum ip_conntrack_dir)(h)->tuple.dst.dir) | 101 | #define DIRECTION(h) ((enum ip_conntrack_dir)(h)->tuple.dst.dir) |
110 | 102 | ||
diff --git a/include/linux/netfilter_ipv6.h b/include/linux/netfilter_ipv6.h index edcc2c6eb5c7..53b2983f6278 100644 --- a/include/linux/netfilter_ipv6.h +++ b/include/linux/netfilter_ipv6.h | |||
@@ -59,6 +59,7 @@ | |||
59 | 59 | ||
60 | enum nf_ip6_hook_priorities { | 60 | enum nf_ip6_hook_priorities { |
61 | NF_IP6_PRI_FIRST = INT_MIN, | 61 | NF_IP6_PRI_FIRST = INT_MIN, |
62 | NF_IP6_PRI_CONNTRACK_DEFRAG = -400, | ||
62 | NF_IP6_PRI_SELINUX_FIRST = -225, | 63 | NF_IP6_PRI_SELINUX_FIRST = -225, |
63 | NF_IP6_PRI_CONNTRACK = -200, | 64 | NF_IP6_PRI_CONNTRACK = -200, |
64 | NF_IP6_PRI_BRIDGE_SABOTAGE_FORWARD = -175, | 65 | NF_IP6_PRI_BRIDGE_SABOTAGE_FORWARD = -175, |
diff --git a/include/linux/netlink.h b/include/linux/netlink.h index ba25ca874c20..6a2ccf78a356 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h | |||
@@ -71,7 +71,8 @@ struct nlmsghdr | |||
71 | 71 | ||
72 | #define NLMSG_ALIGNTO 4 | 72 | #define NLMSG_ALIGNTO 4 |
73 | #define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) ) | 73 | #define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) ) |
74 | #define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(sizeof(struct nlmsghdr))) | 74 | #define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr))) |
75 | #define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN)) | ||
75 | #define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len)) | 76 | #define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len)) |
76 | #define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0))) | 77 | #define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0))) |
77 | #define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \ | 78 | #define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \ |
@@ -86,6 +87,8 @@ struct nlmsghdr | |||
86 | #define NLMSG_DONE 0x3 /* End of a dump */ | 87 | #define NLMSG_DONE 0x3 /* End of a dump */ |
87 | #define NLMSG_OVERRUN 0x4 /* Data lost */ | 88 | #define NLMSG_OVERRUN 0x4 /* Data lost */ |
88 | 89 | ||
90 | #define NLMSG_MIN_TYPE 0x10 /* < 0x10: reserved control messages */ | ||
91 | |||
89 | struct nlmsgerr | 92 | struct nlmsgerr |
90 | { | 93 | { |
91 | int error; | 94 | int error; |
@@ -108,6 +111,25 @@ enum { | |||
108 | NETLINK_CONNECTED, | 111 | NETLINK_CONNECTED, |
109 | }; | 112 | }; |
110 | 113 | ||
114 | /* | ||
115 | * <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)--> | ||
116 | * +---------------------+- - -+- - - - - - - - - -+- - -+ | ||
117 | * | Header | Pad | Payload | Pad | | ||
118 | * | (struct nlattr) | ing | | ing | | ||
119 | * +---------------------+- - -+- - - - - - - - - -+- - -+ | ||
120 | * <-------------- nlattr->nla_len --------------> | ||
121 | */ | ||
122 | |||
123 | struct nlattr | ||
124 | { | ||
125 | __u16 nla_len; | ||
126 | __u16 nla_type; | ||
127 | }; | ||
128 | |||
129 | #define NLA_ALIGNTO 4 | ||
130 | #define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1)) | ||
131 | #define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr))) | ||
132 | |||
111 | #ifdef __KERNEL__ | 133 | #ifdef __KERNEL__ |
112 | 134 | ||
113 | #include <linux/capability.h> | 135 | #include <linux/capability.h> |
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 9a96f0588393..4e06eb0f4451 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h | |||
@@ -387,6 +387,7 @@ | |||
387 | #define PCI_DEVICE_ID_NS_SC1100_SMI 0x0511 | 387 | #define PCI_DEVICE_ID_NS_SC1100_SMI 0x0511 |
388 | #define PCI_DEVICE_ID_NS_SC1100_XBUS 0x0515 | 388 | #define PCI_DEVICE_ID_NS_SC1100_XBUS 0x0515 |
389 | #define PCI_DEVICE_ID_NS_87410 0xd001 | 389 | #define PCI_DEVICE_ID_NS_87410 0xd001 |
390 | #define PCI_DEVICE_ID_NS_CS5535_IDE 0x002d | ||
390 | 391 | ||
391 | #define PCI_VENDOR_ID_TSENG 0x100c | 392 | #define PCI_VENDOR_ID_TSENG 0x100c |
392 | #define PCI_DEVICE_ID_TSENG_W32P_2 0x3202 | 393 | #define PCI_DEVICE_ID_TSENG_W32P_2 0x3202 |
@@ -487,6 +488,8 @@ | |||
487 | #define PCI_DEVICE_ID_AMD_8151_0 0x7454 | 488 | #define PCI_DEVICE_ID_AMD_8151_0 0x7454 |
488 | #define PCI_DEVICE_ID_AMD_8131_APIC 0x7450 | 489 | #define PCI_DEVICE_ID_AMD_8131_APIC 0x7450 |
489 | 490 | ||
491 | #define PCI_DEVICE_ID_AMD_CS5536_IDE 0x209A | ||
492 | |||
490 | #define PCI_VENDOR_ID_TRIDENT 0x1023 | 493 | #define PCI_VENDOR_ID_TRIDENT 0x1023 |
491 | #define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000 | 494 | #define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000 |
492 | #define PCI_DEVICE_ID_TRIDENT_4DWAVE_NX 0x2001 | 495 | #define PCI_DEVICE_ID_TRIDENT_4DWAVE_NX 0x2001 |
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index fdfb8fe8c38c..0a8ea8b35816 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
@@ -274,6 +274,9 @@ struct sk_buff { | |||
274 | #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE) | 274 | #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE) |
275 | __u8 ipvs_property:1; | 275 | __u8 ipvs_property:1; |
276 | #endif | 276 | #endif |
277 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | ||
278 | struct sk_buff *nfct_reasm; | ||
279 | #endif | ||
277 | #ifdef CONFIG_BRIDGE_NETFILTER | 280 | #ifdef CONFIG_BRIDGE_NETFILTER |
278 | struct nf_bridge_info *nf_bridge; | 281 | struct nf_bridge_info *nf_bridge; |
279 | #endif | 282 | #endif |
@@ -1233,8 +1236,7 @@ extern unsigned int datagram_poll(struct file *file, struct socket *sock, | |||
1233 | extern int skb_copy_datagram_iovec(const struct sk_buff *from, | 1236 | extern int skb_copy_datagram_iovec(const struct sk_buff *from, |
1234 | int offset, struct iovec *to, | 1237 | int offset, struct iovec *to, |
1235 | int size); | 1238 | int size); |
1236 | extern int skb_copy_and_csum_datagram_iovec(const | 1239 | extern int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb, |
1237 | struct sk_buff *skb, | ||
1238 | int hlen, | 1240 | int hlen, |
1239 | struct iovec *iov); | 1241 | struct iovec *iov); |
1240 | extern void skb_free_datagram(struct sock *sk, struct sk_buff *skb); | 1242 | extern void skb_free_datagram(struct sock *sk, struct sk_buff *skb); |
@@ -1302,6 +1304,30 @@ static inline void skb_set_timestamp(struct sk_buff *skb, const struct timeval * | |||
1302 | 1304 | ||
1303 | extern void __net_timestamp(struct sk_buff *skb); | 1305 | extern void __net_timestamp(struct sk_buff *skb); |
1304 | 1306 | ||
1307 | extern unsigned int __skb_checksum_complete(struct sk_buff *skb); | ||
1308 | |||
1309 | /** | ||
1310 | * skb_checksum_complete - Calculate checksum of an entire packet | ||
1311 | * @skb: packet to process | ||
1312 | * | ||
1313 | * This function calculates the checksum over the entire packet plus | ||
1314 | * the value of skb->csum. The latter can be used to supply the | ||
1315 | * checksum of a pseudo header as used by TCP/UDP. It returns the | ||
1316 | * checksum. | ||
1317 | * | ||
1318 | * For protocols that contain complete checksums such as ICMP/TCP/UDP, | ||
1319 | * this function can be used to verify that checksum on received | ||
1320 | * packets. In that case the function should return zero if the | ||
1321 | * checksum is correct. In particular, this function will return zero | ||
1322 | * if skb->ip_summed is CHECKSUM_UNNECESSARY which indicates that the | ||
1323 | * hardware has already verified the correctness of the checksum. | ||
1324 | */ | ||
1325 | static inline unsigned int skb_checksum_complete(struct sk_buff *skb) | ||
1326 | { | ||
1327 | return skb->ip_summed != CHECKSUM_UNNECESSARY && | ||
1328 | __skb_checksum_complete(skb); | ||
1329 | } | ||
1330 | |||
1305 | #ifdef CONFIG_NETFILTER | 1331 | #ifdef CONFIG_NETFILTER |
1306 | static inline void nf_conntrack_put(struct nf_conntrack *nfct) | 1332 | static inline void nf_conntrack_put(struct nf_conntrack *nfct) |
1307 | { | 1333 | { |
@@ -1313,10 +1339,26 @@ static inline void nf_conntrack_get(struct nf_conntrack *nfct) | |||
1313 | if (nfct) | 1339 | if (nfct) |
1314 | atomic_inc(&nfct->use); | 1340 | atomic_inc(&nfct->use); |
1315 | } | 1341 | } |
1342 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | ||
1343 | static inline void nf_conntrack_get_reasm(struct sk_buff *skb) | ||
1344 | { | ||
1345 | if (skb) | ||
1346 | atomic_inc(&skb->users); | ||
1347 | } | ||
1348 | static inline void nf_conntrack_put_reasm(struct sk_buff *skb) | ||
1349 | { | ||
1350 | if (skb) | ||
1351 | kfree_skb(skb); | ||
1352 | } | ||
1353 | #endif | ||
1316 | static inline void nf_reset(struct sk_buff *skb) | 1354 | static inline void nf_reset(struct sk_buff *skb) |
1317 | { | 1355 | { |
1318 | nf_conntrack_put(skb->nfct); | 1356 | nf_conntrack_put(skb->nfct); |
1319 | skb->nfct = NULL; | 1357 | skb->nfct = NULL; |
1358 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | ||
1359 | nf_conntrack_put_reasm(skb->nfct_reasm); | ||
1360 | skb->nfct_reasm = NULL; | ||
1361 | #endif | ||
1320 | } | 1362 | } |
1321 | 1363 | ||
1322 | #ifdef CONFIG_BRIDGE_NETFILTER | 1364 | #ifdef CONFIG_BRIDGE_NETFILTER |
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index fc131d6602b9..22cf5e1ac987 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h | |||
@@ -205,6 +205,7 @@ enum | |||
205 | NET_ECONET=16, | 205 | NET_ECONET=16, |
206 | NET_SCTP=17, | 206 | NET_SCTP=17, |
207 | NET_LLC=18, | 207 | NET_LLC=18, |
208 | NET_NETFILTER=19, | ||
208 | }; | 209 | }; |
209 | 210 | ||
210 | /* /proc/sys/kernel/random */ | 211 | /* /proc/sys/kernel/random */ |
@@ -270,6 +271,42 @@ enum | |||
270 | NET_UNIX_MAX_DGRAM_QLEN=3, | 271 | NET_UNIX_MAX_DGRAM_QLEN=3, |
271 | }; | 272 | }; |
272 | 273 | ||
274 | /* /proc/sys/net/netfilter */ | ||
275 | enum | ||
276 | { | ||
277 | NET_NF_CONNTRACK_MAX=1, | ||
278 | NET_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT=2, | ||
279 | NET_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV=3, | ||
280 | NET_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED=4, | ||
281 | NET_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT=5, | ||
282 | NET_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT=6, | ||
283 | NET_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK=7, | ||
284 | NET_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT=8, | ||
285 | NET_NF_CONNTRACK_TCP_TIMEOUT_CLOSE=9, | ||
286 | NET_NF_CONNTRACK_UDP_TIMEOUT=10, | ||
287 | NET_NF_CONNTRACK_UDP_TIMEOUT_STREAM=11, | ||
288 | NET_NF_CONNTRACK_ICMP_TIMEOUT=12, | ||
289 | NET_NF_CONNTRACK_GENERIC_TIMEOUT=13, | ||
290 | NET_NF_CONNTRACK_BUCKETS=14, | ||
291 | NET_NF_CONNTRACK_LOG_INVALID=15, | ||
292 | NET_NF_CONNTRACK_TCP_TIMEOUT_MAX_RETRANS=16, | ||
293 | NET_NF_CONNTRACK_TCP_LOOSE=17, | ||
294 | NET_NF_CONNTRACK_TCP_BE_LIBERAL=18, | ||
295 | NET_NF_CONNTRACK_TCP_MAX_RETRANS=19, | ||
296 | NET_NF_CONNTRACK_SCTP_TIMEOUT_CLOSED=20, | ||
297 | NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_WAIT=21, | ||
298 | NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_ECHOED=22, | ||
299 | NET_NF_CONNTRACK_SCTP_TIMEOUT_ESTABLISHED=23, | ||
300 | NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_SENT=24, | ||
301 | NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD=25, | ||
302 | NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT=26, | ||
303 | NET_NF_CONNTRACK_COUNT=27, | ||
304 | NET_NF_CONNTRACK_ICMPV6_TIMEOUT=28, | ||
305 | NET_NF_CONNTRACK_FRAG6_TIMEOUT=29, | ||
306 | NET_NF_CONNTRACK_FRAG6_LOW_THRESH=30, | ||
307 | NET_NF_CONNTRACK_FRAG6_HIGH_THRESH=31, | ||
308 | }; | ||
309 | |||
273 | /* /proc/sys/net/ipv4 */ | 310 | /* /proc/sys/net/ipv4 */ |
274 | enum | 311 | enum |
275 | { | 312 | { |
diff --git a/include/net/genetlink.h b/include/net/genetlink.h new file mode 100644 index 000000000000..52d8b1a73d52 --- /dev/null +++ b/include/net/genetlink.h | |||
@@ -0,0 +1,154 @@ | |||
1 | #ifndef __NET_GENERIC_NETLINK_H | ||
2 | #define __NET_GENERIC_NETLINK_H | ||
3 | |||
4 | #include <linux/genetlink.h> | ||
5 | #include <net/netlink.h> | ||
6 | |||
7 | /** | ||
8 | * struct genl_family - generic netlink family | ||
9 | * @id: protocol family idenfitier | ||
10 | * @hdrsize: length of user specific header in bytes | ||
11 | * @name: name of family | ||
12 | * @version: protocol version | ||
13 | * @maxattr: maximum number of attributes supported | ||
14 | * @attrbuf: buffer to store parsed attributes | ||
15 | * @ops_list: list of all assigned operations | ||
16 | * @family_list: family list | ||
17 | */ | ||
18 | struct genl_family | ||
19 | { | ||
20 | unsigned int id; | ||
21 | unsigned int hdrsize; | ||
22 | char name[GENL_NAMSIZ]; | ||
23 | unsigned int version; | ||
24 | unsigned int maxattr; | ||
25 | struct module * owner; | ||
26 | struct nlattr ** attrbuf; /* private */ | ||
27 | struct list_head ops_list; /* private */ | ||
28 | struct list_head family_list; /* private */ | ||
29 | }; | ||
30 | |||
31 | #define GENL_ADMIN_PERM 0x01 | ||
32 | |||
33 | /** | ||
34 | * struct genl_info - receiving information | ||
35 | * @snd_seq: sending sequence number | ||
36 | * @snd_pid: netlink pid of sender | ||
37 | * @nlhdr: netlink message header | ||
38 | * @genlhdr: generic netlink message header | ||
39 | * @userhdr: user specific header | ||
40 | * @attrs: netlink attributes | ||
41 | */ | ||
42 | struct genl_info | ||
43 | { | ||
44 | u32 snd_seq; | ||
45 | u32 snd_pid; | ||
46 | struct nlmsghdr * nlhdr; | ||
47 | struct genlmsghdr * genlhdr; | ||
48 | void * userhdr; | ||
49 | struct nlattr ** attrs; | ||
50 | }; | ||
51 | |||
52 | /** | ||
53 | * struct genl_ops - generic netlink operations | ||
54 | * @cmd: command identifier | ||
55 | * @flags: flags | ||
56 | * @policy: attribute validation policy | ||
57 | * @doit: standard command callback | ||
58 | * @dumpit: callback for dumpers | ||
59 | * @ops_list: operations list | ||
60 | */ | ||
61 | struct genl_ops | ||
62 | { | ||
63 | unsigned int cmd; | ||
64 | unsigned int flags; | ||
65 | struct nla_policy *policy; | ||
66 | int (*doit)(struct sk_buff *skb, | ||
67 | struct genl_info *info); | ||
68 | int (*dumpit)(struct sk_buff *skb, | ||
69 | struct netlink_callback *cb); | ||
70 | struct list_head ops_list; | ||
71 | }; | ||
72 | |||
73 | extern int genl_register_family(struct genl_family *family); | ||
74 | extern int genl_unregister_family(struct genl_family *family); | ||
75 | extern int genl_register_ops(struct genl_family *, struct genl_ops *ops); | ||
76 | extern int genl_unregister_ops(struct genl_family *, struct genl_ops *ops); | ||
77 | |||
78 | extern struct sock *genl_sock; | ||
79 | |||
80 | /** | ||
81 | * genlmsg_put - Add generic netlink header to netlink message | ||
82 | * @skb: socket buffer holding the message | ||
83 | * @pid: netlink pid the message is addressed to | ||
84 | * @seq: sequence number (usually the one of the sender) | ||
85 | * @type: netlink message type | ||
86 | * @hdrlen: length of the user specific header | ||
87 | * @flags netlink message flags | ||
88 | * @cmd: generic netlink command | ||
89 | * @version: version | ||
90 | * | ||
91 | * Returns pointer to user specific header | ||
92 | */ | ||
93 | static inline void *genlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, | ||
94 | int type, int hdrlen, int flags, | ||
95 | u8 cmd, u8 version) | ||
96 | { | ||
97 | struct nlmsghdr *nlh; | ||
98 | struct genlmsghdr *hdr; | ||
99 | |||
100 | nlh = nlmsg_put(skb, pid, seq, type, GENL_HDRLEN + hdrlen, flags); | ||
101 | if (nlh == NULL) | ||
102 | return NULL; | ||
103 | |||
104 | hdr = nlmsg_data(nlh); | ||
105 | hdr->cmd = cmd; | ||
106 | hdr->version = version; | ||
107 | hdr->reserved = 0; | ||
108 | |||
109 | return (char *) hdr + GENL_HDRLEN; | ||
110 | } | ||
111 | |||
112 | /** | ||
113 | * genlmsg_end - Finalize a generic netlink message | ||
114 | * @skb: socket buffer the message is stored in | ||
115 | * @hdr: user specific header | ||
116 | */ | ||
117 | static inline int genlmsg_end(struct sk_buff *skb, void *hdr) | ||
118 | { | ||
119 | return nlmsg_end(skb, hdr - GENL_HDRLEN - NLMSG_HDRLEN); | ||
120 | } | ||
121 | |||
122 | /** | ||
123 | * genlmsg_cancel - Cancel construction of a generic netlink message | ||
124 | * @skb: socket buffer the message is stored in | ||
125 | * @hdr: generic netlink message header | ||
126 | */ | ||
127 | static inline int genlmsg_cancel(struct sk_buff *skb, void *hdr) | ||
128 | { | ||
129 | return nlmsg_cancel(skb, hdr - GENL_HDRLEN - NLMSG_HDRLEN); | ||
130 | } | ||
131 | |||
132 | /** | ||
133 | * genlmsg_multicast - multicast a netlink message | ||
134 | * @skb: netlink message as socket buffer | ||
135 | * @pid: own netlink pid to avoid sending to yourself | ||
136 | * @group: multicast group id | ||
137 | */ | ||
138 | static inline int genlmsg_multicast(struct sk_buff *skb, u32 pid, | ||
139 | unsigned int group) | ||
140 | { | ||
141 | return nlmsg_multicast(genl_sock, skb, pid, group); | ||
142 | } | ||
143 | |||
144 | /** | ||
145 | * genlmsg_unicast - unicast a netlink message | ||
146 | * @skb: netlink message as socket buffer | ||
147 | * @pid: netlink pid of the destination socket | ||
148 | */ | ||
149 | static inline int genlmsg_unicast(struct sk_buff *skb, u32 pid) | ||
150 | { | ||
151 | return nlmsg_unicast(genl_sock, skb, pid); | ||
152 | } | ||
153 | |||
154 | #endif /* __NET_GENERIC_NETLINK_H */ | ||
diff --git a/include/net/netfilter/ipv4/nf_conntrack_icmp.h b/include/net/netfilter/ipv4/nf_conntrack_icmp.h new file mode 100644 index 000000000000..3dd22cff23ec --- /dev/null +++ b/include/net/netfilter/ipv4/nf_conntrack_icmp.h | |||
@@ -0,0 +1,11 @@ | |||
1 | #ifndef _NF_CONNTRACK_ICMP_H | ||
2 | #define _NF_CONNTRACK_ICMP_H | ||
3 | /* ICMP tracking. */ | ||
4 | #include <asm/atomic.h> | ||
5 | |||
6 | struct ip_ct_icmp | ||
7 | { | ||
8 | /* Optimization: when number in == number out, forget immediately. */ | ||
9 | atomic_t count; | ||
10 | }; | ||
11 | #endif /* _NF_CONNTRACK_ICMP_H */ | ||
diff --git a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h new file mode 100644 index 000000000000..25b081a730e6 --- /dev/null +++ b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h | |||
@@ -0,0 +1,43 @@ | |||
1 | /* | ||
2 | * IPv4 support for nf_conntrack. | ||
3 | * | ||
4 | * 23 Mar 2004: Yasuyuki Kozakai @ USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
5 | * - move L3 protocol dependent part from include/linux/netfilter_ipv4/ | ||
6 | * ip_conntarck.h | ||
7 | */ | ||
8 | |||
9 | #ifndef _NF_CONNTRACK_IPV4_H | ||
10 | #define _NF_CONNTRACK_IPV4_H | ||
11 | |||
12 | #ifdef CONFIG_IP_NF_NAT_NEEDED | ||
13 | #include <linux/netfilter_ipv4/ip_nat.h> | ||
14 | |||
15 | /* per conntrack: nat application helper private data */ | ||
16 | union ip_conntrack_nat_help { | ||
17 | /* insert nat helper private data here */ | ||
18 | }; | ||
19 | |||
20 | struct nf_conntrack_ipv4_nat { | ||
21 | struct ip_nat_info info; | ||
22 | union ip_conntrack_nat_help help; | ||
23 | #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \ | ||
24 | defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) | ||
25 | int masq_index; | ||
26 | #endif | ||
27 | }; | ||
28 | #endif /* CONFIG_IP_NF_NAT_NEEDED */ | ||
29 | |||
30 | struct nf_conntrack_ipv4 { | ||
31 | #ifdef CONFIG_IP_NF_NAT_NEEDED | ||
32 | struct nf_conntrack_ipv4_nat *nat; | ||
33 | #endif | ||
34 | }; | ||
35 | |||
36 | /* Returns new sk_buff, or NULL */ | ||
37 | struct sk_buff * | ||
38 | nf_ct_ipv4_ct_gather_frags(struct sk_buff *skb); | ||
39 | |||
40 | /* call to create an explicit dependency on nf_conntrack_l3proto_ipv4. */ | ||
41 | extern void need_ip_conntrack(void); | ||
42 | |||
43 | #endif /*_NF_CONNTRACK_IPV4_H*/ | ||
diff --git a/include/net/netfilter/ipv6/nf_conntrack_icmpv6.h b/include/net/netfilter/ipv6/nf_conntrack_icmpv6.h new file mode 100644 index 000000000000..86591afda29c --- /dev/null +++ b/include/net/netfilter/ipv6/nf_conntrack_icmpv6.h | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * ICMPv6 tracking. | ||
3 | * | ||
4 | * 21 Apl 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
5 | * - separated from nf_conntrack_icmp.h | ||
6 | * | ||
7 | * Derived from include/linux/netfiter_ipv4/ip_conntrack_icmp.h | ||
8 | */ | ||
9 | |||
10 | #ifndef _NF_CONNTRACK_ICMPV6_H | ||
11 | #define _NF_CONNTRACK_ICMPV6_H | ||
12 | #include <asm/atomic.h> | ||
13 | |||
14 | #ifndef ICMPV6_NI_QUERY | ||
15 | #define ICMPV6_NI_QUERY 139 | ||
16 | #endif | ||
17 | #ifndef ICMPV6_NI_REPLY | ||
18 | #define ICMPV6_NI_REPLY 140 | ||
19 | #endif | ||
20 | |||
21 | struct nf_ct_icmpv6 | ||
22 | { | ||
23 | /* Optimization: when number in == number out, forget immediately. */ | ||
24 | atomic_t count; | ||
25 | }; | ||
26 | |||
27 | #endif /* _NF_CONNTRACK_ICMPV6_H */ | ||
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h new file mode 100644 index 000000000000..cc4825610795 --- /dev/null +++ b/include/net/netfilter/nf_conntrack.h | |||
@@ -0,0 +1,354 @@ | |||
1 | /* | ||
2 | * Connection state tracking for netfilter. This is separated from, | ||
3 | * but required by, the (future) NAT layer; it can also be used by an iptables | ||
4 | * extension. | ||
5 | * | ||
6 | * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
7 | * - generalize L3 protocol dependent part. | ||
8 | * | ||
9 | * Derived from include/linux/netfiter_ipv4/ip_conntrack.h | ||
10 | */ | ||
11 | |||
12 | #ifndef _NF_CONNTRACK_H | ||
13 | #define _NF_CONNTRACK_H | ||
14 | |||
15 | #include <linux/netfilter/nf_conntrack_common.h> | ||
16 | |||
17 | #ifdef __KERNEL__ | ||
18 | #include <linux/config.h> | ||
19 | #include <linux/bitops.h> | ||
20 | #include <linux/compiler.h> | ||
21 | #include <asm/atomic.h> | ||
22 | |||
23 | #include <linux/netfilter/nf_conntrack_tcp.h> | ||
24 | #include <linux/netfilter/nf_conntrack_sctp.h> | ||
25 | #include <net/netfilter/ipv4/nf_conntrack_icmp.h> | ||
26 | #include <net/netfilter/ipv6/nf_conntrack_icmpv6.h> | ||
27 | |||
28 | #include <net/netfilter/nf_conntrack_tuple.h> | ||
29 | |||
30 | /* per conntrack: protocol private data */ | ||
31 | union nf_conntrack_proto { | ||
32 | /* insert conntrack proto private data here */ | ||
33 | struct ip_ct_sctp sctp; | ||
34 | struct ip_ct_tcp tcp; | ||
35 | struct ip_ct_icmp icmp; | ||
36 | struct nf_ct_icmpv6 icmpv6; | ||
37 | }; | ||
38 | |||
39 | union nf_conntrack_expect_proto { | ||
40 | /* insert expect proto private data here */ | ||
41 | }; | ||
42 | |||
43 | /* Add protocol helper include file here */ | ||
44 | #include <linux/netfilter/nf_conntrack_ftp.h> | ||
45 | |||
46 | /* per conntrack: application helper private data */ | ||
47 | union nf_conntrack_help { | ||
48 | /* insert conntrack helper private data (master) here */ | ||
49 | struct ip_ct_ftp_master ct_ftp_info; | ||
50 | }; | ||
51 | |||
52 | #include <linux/types.h> | ||
53 | #include <linux/skbuff.h> | ||
54 | |||
55 | #ifdef CONFIG_NETFILTER_DEBUG | ||
56 | #define NF_CT_ASSERT(x) \ | ||
57 | do { \ | ||
58 | if (!(x)) \ | ||
59 | /* Wooah! I'm tripping my conntrack in a frenzy of \ | ||
60 | netplay... */ \ | ||
61 | printk("NF_CT_ASSERT: %s:%i(%s)\n", \ | ||
62 | __FILE__, __LINE__, __FUNCTION__); \ | ||
63 | } while(0) | ||
64 | #else | ||
65 | #define NF_CT_ASSERT(x) | ||
66 | #endif | ||
67 | |||
68 | struct nf_conntrack_helper; | ||
69 | |||
70 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> | ||
71 | struct nf_conn | ||
72 | { | ||
73 | /* Usage count in here is 1 for hash table/destruct timer, 1 per skb, | ||
74 | plus 1 for any connection(s) we are `master' for */ | ||
75 | struct nf_conntrack ct_general; | ||
76 | |||
77 | /* XXX should I move this to the tail ? - Y.K */ | ||
78 | /* These are my tuples; original and reply */ | ||
79 | struct nf_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX]; | ||
80 | |||
81 | /* Have we seen traffic both ways yet? (bitset) */ | ||
82 | unsigned long status; | ||
83 | |||
84 | /* Timer function; drops refcnt when it goes off. */ | ||
85 | struct timer_list timeout; | ||
86 | |||
87 | #ifdef CONFIG_NF_CT_ACCT | ||
88 | /* Accounting Information (same cache line as other written members) */ | ||
89 | struct ip_conntrack_counter counters[IP_CT_DIR_MAX]; | ||
90 | #endif | ||
91 | /* If we were expected by an expectation, this will be it */ | ||
92 | struct nf_conn *master; | ||
93 | |||
94 | /* Current number of expected connections */ | ||
95 | unsigned int expecting; | ||
96 | |||
97 | /* Helper. if any */ | ||
98 | struct nf_conntrack_helper *helper; | ||
99 | |||
100 | /* features - nat, helper, ... used by allocating system */ | ||
101 | u_int32_t features; | ||
102 | |||
103 | /* Storage reserved for other modules: */ | ||
104 | |||
105 | union nf_conntrack_proto proto; | ||
106 | |||
107 | #if defined(CONFIG_NF_CONNTRACK_MARK) | ||
108 | u_int32_t mark; | ||
109 | #endif | ||
110 | |||
111 | /* These members are dynamically allocated. */ | ||
112 | |||
113 | union nf_conntrack_help *help; | ||
114 | |||
115 | /* Layer 3 dependent members. (ex: NAT) */ | ||
116 | union { | ||
117 | struct nf_conntrack_ipv4 *ipv4; | ||
118 | } l3proto; | ||
119 | void *data[0]; | ||
120 | }; | ||
121 | |||
122 | struct nf_conntrack_expect | ||
123 | { | ||
124 | /* Internal linked list (global expectation list) */ | ||
125 | struct list_head list; | ||
126 | |||
127 | /* We expect this tuple, with the following mask */ | ||
128 | struct nf_conntrack_tuple tuple, mask; | ||
129 | |||
130 | /* Function to call after setup and insertion */ | ||
131 | void (*expectfn)(struct nf_conn *new, | ||
132 | struct nf_conntrack_expect *this); | ||
133 | |||
134 | /* The conntrack of the master connection */ | ||
135 | struct nf_conn *master; | ||
136 | |||
137 | /* Timer function; deletes the expectation. */ | ||
138 | struct timer_list timeout; | ||
139 | |||
140 | /* Usage count. */ | ||
141 | atomic_t use; | ||
142 | |||
143 | /* Flags */ | ||
144 | unsigned int flags; | ||
145 | |||
146 | #ifdef CONFIG_NF_NAT_NEEDED | ||
147 | /* This is the original per-proto part, used to map the | ||
148 | * expected connection the way the recipient expects. */ | ||
149 | union nf_conntrack_manip_proto saved_proto; | ||
150 | /* Direction relative to the master connection. */ | ||
151 | enum ip_conntrack_dir dir; | ||
152 | #endif | ||
153 | }; | ||
154 | |||
155 | #define NF_CT_EXPECT_PERMANENT 0x1 | ||
156 | |||
157 | static inline struct nf_conn * | ||
158 | nf_ct_tuplehash_to_ctrack(const struct nf_conntrack_tuple_hash *hash) | ||
159 | { | ||
160 | return container_of(hash, struct nf_conn, | ||
161 | tuplehash[hash->tuple.dst.dir]); | ||
162 | } | ||
163 | |||
164 | /* get master conntrack via master expectation */ | ||
165 | #define master_ct(conntr) (conntr->master) | ||
166 | |||
167 | /* Alter reply tuple (maybe alter helper). */ | ||
168 | extern void | ||
169 | nf_conntrack_alter_reply(struct nf_conn *conntrack, | ||
170 | const struct nf_conntrack_tuple *newreply); | ||
171 | |||
172 | /* Is this tuple taken? (ignoring any belonging to the given | ||
173 | conntrack). */ | ||
174 | extern int | ||
175 | nf_conntrack_tuple_taken(const struct nf_conntrack_tuple *tuple, | ||
176 | const struct nf_conn *ignored_conntrack); | ||
177 | |||
178 | /* Return conntrack_info and tuple hash for given skb. */ | ||
179 | static inline struct nf_conn * | ||
180 | nf_ct_get(const struct sk_buff *skb, enum ip_conntrack_info *ctinfo) | ||
181 | { | ||
182 | *ctinfo = skb->nfctinfo; | ||
183 | return (struct nf_conn *)skb->nfct; | ||
184 | } | ||
185 | |||
186 | /* decrement reference count on a conntrack */ | ||
187 | static inline void nf_ct_put(struct nf_conn *ct) | ||
188 | { | ||
189 | NF_CT_ASSERT(ct); | ||
190 | nf_conntrack_put(&ct->ct_general); | ||
191 | } | ||
192 | |||
193 | /* call to create an explicit dependency on nf_conntrack. */ | ||
194 | extern void need_nf_conntrack(void); | ||
195 | |||
196 | extern int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse, | ||
197 | const struct nf_conntrack_tuple *orig); | ||
198 | |||
199 | extern void __nf_ct_refresh_acct(struct nf_conn *ct, | ||
200 | enum ip_conntrack_info ctinfo, | ||
201 | const struct sk_buff *skb, | ||
202 | unsigned long extra_jiffies, | ||
203 | int do_acct); | ||
204 | |||
205 | /* Refresh conntrack for this many jiffies and do accounting */ | ||
206 | static inline void nf_ct_refresh_acct(struct nf_conn *ct, | ||
207 | enum ip_conntrack_info ctinfo, | ||
208 | const struct sk_buff *skb, | ||
209 | unsigned long extra_jiffies) | ||
210 | { | ||
211 | __nf_ct_refresh_acct(ct, ctinfo, skb, extra_jiffies, 1); | ||
212 | } | ||
213 | |||
214 | /* Refresh conntrack for this many jiffies */ | ||
215 | static inline void nf_ct_refresh(struct nf_conn *ct, | ||
216 | const struct sk_buff *skb, | ||
217 | unsigned long extra_jiffies) | ||
218 | { | ||
219 | __nf_ct_refresh_acct(ct, 0, skb, extra_jiffies, 0); | ||
220 | } | ||
221 | |||
222 | /* These are for NAT. Icky. */ | ||
223 | /* Update TCP window tracking data when NAT mangles the packet */ | ||
224 | extern void nf_conntrack_tcp_update(struct sk_buff *skb, | ||
225 | unsigned int dataoff, | ||
226 | struct nf_conn *conntrack, | ||
227 | int dir); | ||
228 | |||
229 | /* Call me when a conntrack is destroyed. */ | ||
230 | extern void (*nf_conntrack_destroyed)(struct nf_conn *conntrack); | ||
231 | |||
232 | /* Fake conntrack entry for untracked connections */ | ||
233 | extern struct nf_conn nf_conntrack_untracked; | ||
234 | |||
235 | extern int nf_ct_no_defrag; | ||
236 | |||
237 | /* Iterate over all conntracks: if iter returns true, it's deleted. */ | ||
238 | extern void | ||
239 | nf_ct_iterate_cleanup(int (*iter)(struct nf_conn *i, void *data), void *data); | ||
240 | extern void nf_conntrack_free(struct nf_conn *ct); | ||
241 | extern struct nf_conn * | ||
242 | nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, | ||
243 | const struct nf_conntrack_tuple *repl); | ||
244 | |||
245 | /* It's confirmed if it is, or has been in the hash table. */ | ||
246 | static inline int nf_ct_is_confirmed(struct nf_conn *ct) | ||
247 | { | ||
248 | return test_bit(IPS_CONFIRMED_BIT, &ct->status); | ||
249 | } | ||
250 | |||
251 | static inline int nf_ct_is_dying(struct nf_conn *ct) | ||
252 | { | ||
253 | return test_bit(IPS_DYING_BIT, &ct->status); | ||
254 | } | ||
255 | |||
256 | extern unsigned int nf_conntrack_htable_size; | ||
257 | |||
258 | #define NF_CT_STAT_INC(count) (__get_cpu_var(nf_conntrack_stat).count++) | ||
259 | |||
260 | #ifdef CONFIG_NF_CONNTRACK_EVENTS | ||
261 | #include <linux/notifier.h> | ||
262 | #include <linux/interrupt.h> | ||
263 | |||
264 | struct nf_conntrack_ecache { | ||
265 | struct nf_conn *ct; | ||
266 | unsigned int events; | ||
267 | }; | ||
268 | DECLARE_PER_CPU(struct nf_conntrack_ecache, nf_conntrack_ecache); | ||
269 | |||
270 | #define CONNTRACK_ECACHE(x) (__get_cpu_var(nf_conntrack_ecache).x) | ||
271 | |||
272 | extern struct notifier_block *nf_conntrack_chain; | ||
273 | extern struct notifier_block *nf_conntrack_expect_chain; | ||
274 | |||
275 | static inline int nf_conntrack_register_notifier(struct notifier_block *nb) | ||
276 | { | ||
277 | return notifier_chain_register(&nf_conntrack_chain, nb); | ||
278 | } | ||
279 | |||
280 | static inline int nf_conntrack_unregister_notifier(struct notifier_block *nb) | ||
281 | { | ||
282 | return notifier_chain_unregister(&nf_conntrack_chain, nb); | ||
283 | } | ||
284 | |||
285 | static inline int | ||
286 | nf_conntrack_expect_register_notifier(struct notifier_block *nb) | ||
287 | { | ||
288 | return notifier_chain_register(&nf_conntrack_expect_chain, nb); | ||
289 | } | ||
290 | |||
291 | static inline int | ||
292 | nf_conntrack_expect_unregister_notifier(struct notifier_block *nb) | ||
293 | { | ||
294 | return notifier_chain_unregister(&nf_conntrack_expect_chain, nb); | ||
295 | } | ||
296 | |||
297 | extern void nf_ct_deliver_cached_events(const struct nf_conn *ct); | ||
298 | extern void __nf_ct_event_cache_init(struct nf_conn *ct); | ||
299 | |||
300 | static inline void | ||
301 | nf_conntrack_event_cache(enum ip_conntrack_events event, | ||
302 | const struct sk_buff *skb) | ||
303 | { | ||
304 | struct nf_conn *ct = (struct nf_conn *)skb->nfct; | ||
305 | struct nf_conntrack_ecache *ecache; | ||
306 | |||
307 | local_bh_disable(); | ||
308 | ecache = &__get_cpu_var(nf_conntrack_ecache); | ||
309 | if (ct != ecache->ct) | ||
310 | __nf_ct_event_cache_init(ct); | ||
311 | ecache->events |= event; | ||
312 | local_bh_enable(); | ||
313 | } | ||
314 | |||
315 | static inline void nf_conntrack_event(enum ip_conntrack_events event, | ||
316 | struct nf_conn *ct) | ||
317 | { | ||
318 | if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) | ||
319 | notifier_call_chain(&nf_conntrack_chain, event, ct); | ||
320 | } | ||
321 | |||
322 | static inline void | ||
323 | nf_conntrack_expect_event(enum ip_conntrack_expect_events event, | ||
324 | struct nf_conntrack_expect *exp) | ||
325 | { | ||
326 | notifier_call_chain(&nf_conntrack_expect_chain, event, exp); | ||
327 | } | ||
328 | #else /* CONFIG_NF_CONNTRACK_EVENTS */ | ||
329 | static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, | ||
330 | const struct sk_buff *skb) {} | ||
331 | static inline void nf_conntrack_event(enum ip_conntrack_events event, | ||
332 | struct nf_conn *ct) {} | ||
333 | static inline void nf_ct_deliver_cached_events(const struct nf_conn *ct) {} | ||
334 | static inline void | ||
335 | nf_conntrack_expect_event(enum ip_conntrack_expect_events event, | ||
336 | struct nf_conntrack_expect *exp) {} | ||
337 | #endif /* CONFIG_NF_CONNTRACK_EVENTS */ | ||
338 | |||
339 | /* no helper, no nat */ | ||
340 | #define NF_CT_F_BASIC 0 | ||
341 | /* for helper */ | ||
342 | #define NF_CT_F_HELP 1 | ||
343 | /* for nat. */ | ||
344 | #define NF_CT_F_NAT 2 | ||
345 | #define NF_CT_F_NUM 4 | ||
346 | |||
347 | extern int | ||
348 | nf_conntrack_register_cache(u_int32_t features, const char *name, size_t size, | ||
349 | int (*init_conntrack)(struct nf_conn *, u_int32_t)); | ||
350 | extern void | ||
351 | nf_conntrack_unregister_cache(u_int32_t features); | ||
352 | |||
353 | #endif /* __KERNEL__ */ | ||
354 | #endif /* _NF_CONNTRACK_H */ | ||
diff --git a/include/net/netfilter/nf_conntrack_compat.h b/include/net/netfilter/nf_conntrack_compat.h new file mode 100644 index 000000000000..3cac19fb3648 --- /dev/null +++ b/include/net/netfilter/nf_conntrack_compat.h | |||
@@ -0,0 +1,108 @@ | |||
1 | #ifndef _NF_CONNTRACK_COMPAT_H | ||
2 | #define _NF_CONNTRACK_COMPAT_H | ||
3 | |||
4 | #ifdef __KERNEL__ | ||
5 | |||
6 | #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) | ||
7 | |||
8 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
9 | |||
10 | #ifdef CONFIG_IP_NF_CONNTRACK_MARK | ||
11 | static inline u_int32_t *nf_ct_get_mark(const struct sk_buff *skb, | ||
12 | u_int32_t *ctinfo) | ||
13 | { | ||
14 | struct ip_conntrack *ct = ip_conntrack_get(skb, ctinfo); | ||
15 | |||
16 | if (ct) | ||
17 | return &ct->mark; | ||
18 | else | ||
19 | return NULL; | ||
20 | } | ||
21 | #endif /* CONFIG_IP_NF_CONNTRACK_MARK */ | ||
22 | |||
23 | #ifdef CONFIG_IP_NF_CT_ACCT | ||
24 | static inline struct ip_conntrack_counter * | ||
25 | nf_ct_get_counters(const struct sk_buff *skb) | ||
26 | { | ||
27 | enum ip_conntrack_info ctinfo; | ||
28 | struct ip_conntrack *ct = ip_conntrack_get(skb, &ctinfo); | ||
29 | |||
30 | if (ct) | ||
31 | return ct->counters; | ||
32 | else | ||
33 | return NULL; | ||
34 | } | ||
35 | #endif /* CONFIG_IP_NF_CT_ACCT */ | ||
36 | |||
37 | static inline int nf_ct_is_untracked(const struct sk_buff *skb) | ||
38 | { | ||
39 | return (skb->nfct == &ip_conntrack_untracked.ct_general); | ||
40 | } | ||
41 | |||
42 | static inline void nf_ct_untrack(struct sk_buff *skb) | ||
43 | { | ||
44 | skb->nfct = &ip_conntrack_untracked.ct_general; | ||
45 | } | ||
46 | |||
47 | static inline int nf_ct_get_ctinfo(const struct sk_buff *skb, | ||
48 | enum ip_conntrack_info *ctinfo) | ||
49 | { | ||
50 | struct ip_conntrack *ct = ip_conntrack_get(skb, ctinfo); | ||
51 | return (ct != NULL); | ||
52 | } | ||
53 | |||
54 | #else /* CONFIG_IP_NF_CONNTRACK */ | ||
55 | |||
56 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> | ||
57 | #include <net/netfilter/nf_conntrack.h> | ||
58 | |||
59 | #ifdef CONFIG_NF_CONNTRACK_MARK | ||
60 | |||
61 | static inline u_int32_t *nf_ct_get_mark(const struct sk_buff *skb, | ||
62 | u_int32_t *ctinfo) | ||
63 | { | ||
64 | struct nf_conn *ct = nf_ct_get(skb, ctinfo); | ||
65 | |||
66 | if (ct) | ||
67 | return &ct->mark; | ||
68 | else | ||
69 | return NULL; | ||
70 | } | ||
71 | #endif /* CONFIG_NF_CONNTRACK_MARK */ | ||
72 | |||
73 | #ifdef CONFIG_NF_CT_ACCT | ||
74 | static inline struct ip_conntrack_counter * | ||
75 | nf_ct_get_counters(const struct sk_buff *skb) | ||
76 | { | ||
77 | enum ip_conntrack_info ctinfo; | ||
78 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | ||
79 | |||
80 | if (ct) | ||
81 | return ct->counters; | ||
82 | else | ||
83 | return NULL; | ||
84 | } | ||
85 | #endif /* CONFIG_NF_CT_ACCT */ | ||
86 | |||
87 | static inline int nf_ct_is_untracked(const struct sk_buff *skb) | ||
88 | { | ||
89 | return (skb->nfct == &nf_conntrack_untracked.ct_general); | ||
90 | } | ||
91 | |||
92 | static inline void nf_ct_untrack(struct sk_buff *skb) | ||
93 | { | ||
94 | skb->nfct = &nf_conntrack_untracked.ct_general; | ||
95 | } | ||
96 | |||
97 | static inline int nf_ct_get_ctinfo(const struct sk_buff *skb, | ||
98 | enum ip_conntrack_info *ctinfo) | ||
99 | { | ||
100 | struct nf_conn *ct = nf_ct_get(skb, ctinfo); | ||
101 | return (ct != NULL); | ||
102 | } | ||
103 | |||
104 | #endif /* CONFIG_IP_NF_CONNTRACK */ | ||
105 | |||
106 | #endif /* __KERNEL__ */ | ||
107 | |||
108 | #endif /* _NF_CONNTRACK_COMPAT_H */ | ||
diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h new file mode 100644 index 000000000000..da254525a4ce --- /dev/null +++ b/include/net/netfilter/nf_conntrack_core.h | |||
@@ -0,0 +1,76 @@ | |||
1 | /* | ||
2 | * This header is used to share core functionality between the | ||
3 | * standalone connection tracking module, and the compatibility layer's use | ||
4 | * of connection tracking. | ||
5 | * | ||
6 | * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
7 | * - generalize L3 protocol dependent part. | ||
8 | * | ||
9 | * Derived from include/linux/netfiter_ipv4/ip_conntrack_core.h | ||
10 | */ | ||
11 | |||
12 | #ifndef _NF_CONNTRACK_CORE_H | ||
13 | #define _NF_CONNTRACK_CORE_H | ||
14 | |||
15 | #include <linux/netfilter.h> | ||
16 | |||
17 | /* This header is used to share core functionality between the | ||
18 | standalone connection tracking module, and the compatibility layer's use | ||
19 | of connection tracking. */ | ||
20 | extern unsigned int nf_conntrack_in(int pf, | ||
21 | unsigned int hooknum, | ||
22 | struct sk_buff **pskb); | ||
23 | |||
24 | extern int nf_conntrack_init(void); | ||
25 | extern void nf_conntrack_cleanup(void); | ||
26 | |||
27 | struct nf_conntrack_l3proto; | ||
28 | extern struct nf_conntrack_l3proto *nf_ct_find_l3proto(u_int16_t pf); | ||
29 | /* Like above, but you already have conntrack read lock. */ | ||
30 | extern struct nf_conntrack_l3proto *__nf_ct_find_l3proto(u_int16_t l3proto); | ||
31 | |||
32 | struct nf_conntrack_protocol; | ||
33 | |||
34 | extern int | ||
35 | nf_ct_get_tuple(const struct sk_buff *skb, | ||
36 | unsigned int nhoff, | ||
37 | unsigned int dataoff, | ||
38 | u_int16_t l3num, | ||
39 | u_int8_t protonum, | ||
40 | struct nf_conntrack_tuple *tuple, | ||
41 | const struct nf_conntrack_l3proto *l3proto, | ||
42 | const struct nf_conntrack_protocol *protocol); | ||
43 | |||
44 | extern int | ||
45 | nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse, | ||
46 | const struct nf_conntrack_tuple *orig, | ||
47 | const struct nf_conntrack_l3proto *l3proto, | ||
48 | const struct nf_conntrack_protocol *protocol); | ||
49 | |||
50 | /* Find a connection corresponding to a tuple. */ | ||
51 | extern struct nf_conntrack_tuple_hash * | ||
52 | nf_conntrack_find_get(const struct nf_conntrack_tuple *tuple, | ||
53 | const struct nf_conn *ignored_conntrack); | ||
54 | |||
55 | extern int __nf_conntrack_confirm(struct sk_buff **pskb); | ||
56 | |||
57 | /* Confirm a connection: returns NF_DROP if packet must be dropped. */ | ||
58 | static inline int nf_conntrack_confirm(struct sk_buff **pskb) | ||
59 | { | ||
60 | struct nf_conn *ct = (struct nf_conn *)(*pskb)->nfct; | ||
61 | int ret = NF_ACCEPT; | ||
62 | |||
63 | if (ct) { | ||
64 | if (!nf_ct_is_confirmed(ct)) | ||
65 | ret = __nf_conntrack_confirm(pskb); | ||
66 | nf_ct_deliver_cached_events(ct); | ||
67 | } | ||
68 | return ret; | ||
69 | } | ||
70 | |||
71 | extern void __nf_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb); | ||
72 | |||
73 | extern struct list_head *nf_conntrack_hash; | ||
74 | extern struct list_head nf_conntrack_expect_list; | ||
75 | extern rwlock_t nf_conntrack_lock ; | ||
76 | #endif /* _NF_CONNTRACK_CORE_H */ | ||
diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h new file mode 100644 index 000000000000..5a66b2a3a623 --- /dev/null +++ b/include/net/netfilter/nf_conntrack_helper.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * connection tracking helpers. | ||
3 | * | ||
4 | * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
5 | * - generalize L3 protocol dependent part. | ||
6 | * | ||
7 | * Derived from include/linux/netfiter_ipv4/ip_conntrack_helper.h | ||
8 | */ | ||
9 | |||
10 | #ifndef _NF_CONNTRACK_HELPER_H | ||
11 | #define _NF_CONNTRACK_HELPER_H | ||
12 | #include <net/netfilter/nf_conntrack.h> | ||
13 | |||
14 | struct module; | ||
15 | |||
16 | struct nf_conntrack_helper | ||
17 | { | ||
18 | struct list_head list; /* Internal use. */ | ||
19 | |||
20 | const char *name; /* name of the module */ | ||
21 | struct module *me; /* pointer to self */ | ||
22 | unsigned int max_expected; /* Maximum number of concurrent | ||
23 | * expected connections */ | ||
24 | unsigned int timeout; /* timeout for expecteds */ | ||
25 | |||
26 | /* Mask of things we will help (compared against server response) */ | ||
27 | struct nf_conntrack_tuple tuple; | ||
28 | struct nf_conntrack_tuple mask; | ||
29 | |||
30 | /* Function to call when data passes; return verdict, or -1 to | ||
31 | invalidate. */ | ||
32 | int (*help)(struct sk_buff **pskb, | ||
33 | unsigned int protoff, | ||
34 | struct nf_conn *ct, | ||
35 | enum ip_conntrack_info conntrackinfo); | ||
36 | }; | ||
37 | |||
38 | extern int nf_conntrack_helper_register(struct nf_conntrack_helper *); | ||
39 | extern void nf_conntrack_helper_unregister(struct nf_conntrack_helper *); | ||
40 | |||
41 | /* Allocate space for an expectation: this is mandatory before calling | ||
42 | nf_conntrack_expect_related. You will have to call put afterwards. */ | ||
43 | extern struct nf_conntrack_expect * | ||
44 | nf_conntrack_expect_alloc(struct nf_conn *master); | ||
45 | extern void nf_conntrack_expect_put(struct nf_conntrack_expect *exp); | ||
46 | |||
47 | /* Add an expected connection: can have more than one per connection */ | ||
48 | extern int nf_conntrack_expect_related(struct nf_conntrack_expect *exp); | ||
49 | extern void nf_conntrack_unexpect_related(struct nf_conntrack_expect *exp); | ||
50 | |||
51 | #endif /*_NF_CONNTRACK_HELPER_H*/ | ||
diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h new file mode 100644 index 000000000000..01663e5b33df --- /dev/null +++ b/include/net/netfilter/nf_conntrack_l3proto.h | |||
@@ -0,0 +1,93 @@ | |||
1 | /* | ||
2 | * Copyright (C)2003,2004 USAGI/WIDE Project | ||
3 | * | ||
4 | * Header for use in defining a given L3 protocol for connection tracking. | ||
5 | * | ||
6 | * Author: | ||
7 | * Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
8 | * | ||
9 | * Derived from include/netfilter_ipv4/ip_conntrack_protocol.h | ||
10 | */ | ||
11 | |||
12 | #ifndef _NF_CONNTRACK_L3PROTO_H | ||
13 | #define _NF_CONNTRACK_L3PROTO_H | ||
14 | #include <linux/seq_file.h> | ||
15 | #include <net/netfilter/nf_conntrack.h> | ||
16 | |||
17 | struct nf_conntrack_l3proto | ||
18 | { | ||
19 | /* Next pointer. */ | ||
20 | struct list_head list; | ||
21 | |||
22 | /* L3 Protocol Family number. ex) PF_INET */ | ||
23 | u_int16_t l3proto; | ||
24 | |||
25 | /* Protocol name */ | ||
26 | const char *name; | ||
27 | |||
28 | /* | ||
29 | * Try to fill in the third arg: nhoff is offset of l3 proto | ||
30 | * hdr. Return true if possible. | ||
31 | */ | ||
32 | int (*pkt_to_tuple)(const struct sk_buff *skb, unsigned int nhoff, | ||
33 | struct nf_conntrack_tuple *tuple); | ||
34 | |||
35 | /* | ||
36 | * Invert the per-proto part of the tuple: ie. turn xmit into reply. | ||
37 | * Some packets can't be inverted: return 0 in that case. | ||
38 | */ | ||
39 | int (*invert_tuple)(struct nf_conntrack_tuple *inverse, | ||
40 | const struct nf_conntrack_tuple *orig); | ||
41 | |||
42 | /* Print out the per-protocol part of the tuple. */ | ||
43 | int (*print_tuple)(struct seq_file *s, | ||
44 | const struct nf_conntrack_tuple *); | ||
45 | |||
46 | /* Print out the private part of the conntrack. */ | ||
47 | int (*print_conntrack)(struct seq_file *s, const struct nf_conn *); | ||
48 | |||
49 | /* Returns verdict for packet, or -1 for invalid. */ | ||
50 | int (*packet)(struct nf_conn *conntrack, | ||
51 | const struct sk_buff *skb, | ||
52 | enum ip_conntrack_info ctinfo); | ||
53 | |||
54 | /* | ||
55 | * Called when a new connection for this protocol found; | ||
56 | * returns TRUE if it's OK. If so, packet() called next. | ||
57 | */ | ||
58 | int (*new)(struct nf_conn *conntrack, const struct sk_buff *skb); | ||
59 | |||
60 | /* Called when a conntrack entry is destroyed */ | ||
61 | void (*destroy)(struct nf_conn *conntrack); | ||
62 | |||
63 | /* | ||
64 | * Called before tracking. | ||
65 | * *dataoff: offset of protocol header (TCP, UDP,...) in *pskb | ||
66 | * *protonum: protocol number | ||
67 | */ | ||
68 | int (*prepare)(struct sk_buff **pskb, unsigned int hooknum, | ||
69 | unsigned int *dataoff, u_int8_t *protonum); | ||
70 | |||
71 | u_int32_t (*get_features)(const struct nf_conntrack_tuple *tuple); | ||
72 | |||
73 | /* Module (if any) which this is connected to. */ | ||
74 | struct module *me; | ||
75 | }; | ||
76 | |||
77 | extern struct nf_conntrack_l3proto *nf_ct_l3protos[AF_MAX]; | ||
78 | |||
79 | /* Protocol registration. */ | ||
80 | extern int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto); | ||
81 | extern void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto); | ||
82 | |||
83 | static inline struct nf_conntrack_l3proto * | ||
84 | nf_ct_find_l3proto(u_int16_t l3proto) | ||
85 | { | ||
86 | return nf_ct_l3protos[l3proto]; | ||
87 | } | ||
88 | |||
89 | /* Existing built-in protocols */ | ||
90 | extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4; | ||
91 | extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6; | ||
92 | extern struct nf_conntrack_l3proto nf_conntrack_generic_l3proto; | ||
93 | #endif /*_NF_CONNTRACK_L3PROTO_H*/ | ||
diff --git a/include/net/netfilter/nf_conntrack_protocol.h b/include/net/netfilter/nf_conntrack_protocol.h new file mode 100644 index 000000000000..b3afda35397a --- /dev/null +++ b/include/net/netfilter/nf_conntrack_protocol.h | |||
@@ -0,0 +1,105 @@ | |||
1 | /* | ||
2 | * Header for use in defining a given protocol for connection tracking. | ||
3 | * | ||
4 | * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
5 | * - generalized L3 protocol dependent part. | ||
6 | * | ||
7 | * Derived from include/linux/netfiter_ipv4/ip_conntrack_protcol.h | ||
8 | */ | ||
9 | |||
10 | #ifndef _NF_CONNTRACK_PROTOCOL_H | ||
11 | #define _NF_CONNTRACK_PROTOCOL_H | ||
12 | #include <net/netfilter/nf_conntrack.h> | ||
13 | |||
14 | struct seq_file; | ||
15 | |||
16 | struct nf_conntrack_protocol | ||
17 | { | ||
18 | /* Next pointer. */ | ||
19 | struct list_head list; | ||
20 | |||
21 | /* L3 Protocol number. */ | ||
22 | u_int16_t l3proto; | ||
23 | |||
24 | /* Protocol number. */ | ||
25 | u_int8_t proto; | ||
26 | |||
27 | /* Protocol name */ | ||
28 | const char *name; | ||
29 | |||
30 | /* Try to fill in the third arg: dataoff is offset past network protocol | ||
31 | hdr. Return true if possible. */ | ||
32 | int (*pkt_to_tuple)(const struct sk_buff *skb, | ||
33 | unsigned int dataoff, | ||
34 | struct nf_conntrack_tuple *tuple); | ||
35 | |||
36 | /* Invert the per-proto part of the tuple: ie. turn xmit into reply. | ||
37 | * Some packets can't be inverted: return 0 in that case. | ||
38 | */ | ||
39 | int (*invert_tuple)(struct nf_conntrack_tuple *inverse, | ||
40 | const struct nf_conntrack_tuple *orig); | ||
41 | |||
42 | /* Print out the per-protocol part of the tuple. Return like seq_* */ | ||
43 | int (*print_tuple)(struct seq_file *s, | ||
44 | const struct nf_conntrack_tuple *); | ||
45 | |||
46 | /* Print out the private part of the conntrack. */ | ||
47 | int (*print_conntrack)(struct seq_file *s, const struct nf_conn *); | ||
48 | |||
49 | /* Returns verdict for packet, or -1 for invalid. */ | ||
50 | int (*packet)(struct nf_conn *conntrack, | ||
51 | const struct sk_buff *skb, | ||
52 | unsigned int dataoff, | ||
53 | enum ip_conntrack_info ctinfo, | ||
54 | int pf, | ||
55 | unsigned int hooknum); | ||
56 | |||
57 | /* Called when a new connection for this protocol found; | ||
58 | * returns TRUE if it's OK. If so, packet() called next. */ | ||
59 | int (*new)(struct nf_conn *conntrack, const struct sk_buff *skb, | ||
60 | unsigned int dataoff); | ||
61 | |||
62 | /* Called when a conntrack entry is destroyed */ | ||
63 | void (*destroy)(struct nf_conn *conntrack); | ||
64 | |||
65 | int (*error)(struct sk_buff *skb, unsigned int dataoff, | ||
66 | enum ip_conntrack_info *ctinfo, | ||
67 | int pf, unsigned int hooknum); | ||
68 | |||
69 | /* Module (if any) which this is connected to. */ | ||
70 | struct module *me; | ||
71 | }; | ||
72 | |||
73 | /* Existing built-in protocols */ | ||
74 | extern struct nf_conntrack_protocol nf_conntrack_protocol_tcp6; | ||
75 | extern struct nf_conntrack_protocol nf_conntrack_protocol_udp4; | ||
76 | extern struct nf_conntrack_protocol nf_conntrack_protocol_udp6; | ||
77 | extern struct nf_conntrack_protocol nf_conntrack_generic_protocol; | ||
78 | |||
79 | #define MAX_NF_CT_PROTO 256 | ||
80 | extern struct nf_conntrack_protocol **nf_ct_protos[PF_MAX]; | ||
81 | |||
82 | extern struct nf_conntrack_protocol * | ||
83 | nf_ct_find_proto(u_int16_t l3proto, u_int8_t protocol); | ||
84 | |||
85 | /* Protocol registration. */ | ||
86 | extern int nf_conntrack_protocol_register(struct nf_conntrack_protocol *proto); | ||
87 | extern void nf_conntrack_protocol_unregister(struct nf_conntrack_protocol *proto); | ||
88 | |||
89 | /* Log invalid packets */ | ||
90 | extern unsigned int nf_ct_log_invalid; | ||
91 | |||
92 | #ifdef CONFIG_SYSCTL | ||
93 | #ifdef DEBUG_INVALID_PACKETS | ||
94 | #define LOG_INVALID(proto) \ | ||
95 | (nf_ct_log_invalid == (proto) || nf_ct_log_invalid == IPPROTO_RAW) | ||
96 | #else | ||
97 | #define LOG_INVALID(proto) \ | ||
98 | ((nf_ct_log_invalid == (proto) || nf_ct_log_invalid == IPPROTO_RAW) \ | ||
99 | && net_ratelimit()) | ||
100 | #endif | ||
101 | #else | ||
102 | #define LOG_INVALID(proto) 0 | ||
103 | #endif /* CONFIG_SYSCTL */ | ||
104 | |||
105 | #endif /*_NF_CONNTRACK_PROTOCOL_H*/ | ||
diff --git a/include/net/netfilter/nf_conntrack_tuple.h b/include/net/netfilter/nf_conntrack_tuple.h new file mode 100644 index 000000000000..14ce790e5c65 --- /dev/null +++ b/include/net/netfilter/nf_conntrack_tuple.h | |||
@@ -0,0 +1,190 @@ | |||
1 | /* | ||
2 | * Definitions and Declarations for tuple. | ||
3 | * | ||
4 | * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
5 | * - generalize L3 protocol dependent part. | ||
6 | * | ||
7 | * Derived from include/linux/netfiter_ipv4/ip_conntrack_tuple.h | ||
8 | */ | ||
9 | |||
10 | #ifndef _NF_CONNTRACK_TUPLE_H | ||
11 | #define _NF_CONNTRACK_TUPLE_H | ||
12 | |||
13 | #include <linux/netfilter/nf_conntrack_tuple_common.h> | ||
14 | |||
15 | /* A `tuple' is a structure containing the information to uniquely | ||
16 | identify a connection. ie. if two packets have the same tuple, they | ||
17 | are in the same connection; if not, they are not. | ||
18 | |||
19 | We divide the structure along "manipulatable" and | ||
20 | "non-manipulatable" lines, for the benefit of the NAT code. | ||
21 | */ | ||
22 | |||
23 | #define NF_CT_TUPLE_L3SIZE 4 | ||
24 | |||
25 | /* The l3 protocol-specific manipulable parts of the tuple: always in | ||
26 | network order! */ | ||
27 | union nf_conntrack_man_l3proto { | ||
28 | u_int32_t all[NF_CT_TUPLE_L3SIZE]; | ||
29 | u_int32_t ip; | ||
30 | u_int32_t ip6[4]; | ||
31 | }; | ||
32 | |||
33 | /* The protocol-specific manipulable parts of the tuple: always in | ||
34 | network order! */ | ||
35 | union nf_conntrack_man_proto | ||
36 | { | ||
37 | /* Add other protocols here. */ | ||
38 | u_int16_t all; | ||
39 | |||
40 | struct { | ||
41 | u_int16_t port; | ||
42 | } tcp; | ||
43 | struct { | ||
44 | u_int16_t port; | ||
45 | } udp; | ||
46 | struct { | ||
47 | u_int16_t id; | ||
48 | } icmp; | ||
49 | struct { | ||
50 | u_int16_t port; | ||
51 | } sctp; | ||
52 | }; | ||
53 | |||
54 | /* The manipulable part of the tuple. */ | ||
55 | struct nf_conntrack_man | ||
56 | { | ||
57 | union nf_conntrack_man_l3proto u3; | ||
58 | union nf_conntrack_man_proto u; | ||
59 | /* Layer 3 protocol */ | ||
60 | u_int16_t l3num; | ||
61 | }; | ||
62 | |||
63 | /* This contains the information to distinguish a connection. */ | ||
64 | struct nf_conntrack_tuple | ||
65 | { | ||
66 | struct nf_conntrack_man src; | ||
67 | |||
68 | /* These are the parts of the tuple which are fixed. */ | ||
69 | struct { | ||
70 | union { | ||
71 | u_int32_t all[NF_CT_TUPLE_L3SIZE]; | ||
72 | u_int32_t ip; | ||
73 | u_int32_t ip6[4]; | ||
74 | } u3; | ||
75 | union { | ||
76 | /* Add other protocols here. */ | ||
77 | u_int16_t all; | ||
78 | |||
79 | struct { | ||
80 | u_int16_t port; | ||
81 | } tcp; | ||
82 | struct { | ||
83 | u_int16_t port; | ||
84 | } udp; | ||
85 | struct { | ||
86 | u_int8_t type, code; | ||
87 | } icmp; | ||
88 | struct { | ||
89 | u_int16_t port; | ||
90 | } sctp; | ||
91 | } u; | ||
92 | |||
93 | /* The protocol. */ | ||
94 | u_int8_t protonum; | ||
95 | |||
96 | /* The direction (for tuplehash) */ | ||
97 | u_int8_t dir; | ||
98 | } dst; | ||
99 | }; | ||
100 | |||
101 | /* This is optimized opposed to a memset of the whole structure. Everything we | ||
102 | * really care about is the source/destination unions */ | ||
103 | #define NF_CT_TUPLE_U_BLANK(tuple) \ | ||
104 | do { \ | ||
105 | (tuple)->src.u.all = 0; \ | ||
106 | (tuple)->dst.u.all = 0; \ | ||
107 | memset(&(tuple)->src.u3, 0, sizeof((tuple)->src.u3)); \ | ||
108 | memset(&(tuple)->dst.u3, 0, sizeof((tuple)->dst.u3)); \ | ||
109 | } while (0) | ||
110 | |||
111 | #ifdef __KERNEL__ | ||
112 | |||
113 | #define NF_CT_DUMP_TUPLE(tp) \ | ||
114 | DEBUGP("tuple %p: %u %u %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x %hu -> %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x %hu\n", \ | ||
115 | (tp), (tp)->src.l3num, (tp)->dst.protonum, \ | ||
116 | NIP6(*(struct in6_addr *)(tp)->src.u3.all), ntohs((tp)->src.u.all), \ | ||
117 | NIP6(*(struct in6_addr *)(tp)->dst.u3.all), ntohs((tp)->dst.u.all)) | ||
118 | |||
119 | /* If we're the first tuple, it's the original dir. */ | ||
120 | #define NF_CT_DIRECTION(h) \ | ||
121 | ((enum ip_conntrack_dir)(h)->tuple.dst.dir) | ||
122 | |||
123 | /* Connections have two entries in the hash table: one for each way */ | ||
124 | struct nf_conntrack_tuple_hash | ||
125 | { | ||
126 | struct list_head list; | ||
127 | |||
128 | struct nf_conntrack_tuple tuple; | ||
129 | }; | ||
130 | |||
131 | #endif /* __KERNEL__ */ | ||
132 | |||
133 | static inline int nf_ct_tuple_src_equal(const struct nf_conntrack_tuple *t1, | ||
134 | const struct nf_conntrack_tuple *t2) | ||
135 | { | ||
136 | return (t1->src.u3.all[0] == t2->src.u3.all[0] && | ||
137 | t1->src.u3.all[1] == t2->src.u3.all[1] && | ||
138 | t1->src.u3.all[2] == t2->src.u3.all[2] && | ||
139 | t1->src.u3.all[3] == t2->src.u3.all[3] && | ||
140 | t1->src.u.all == t2->src.u.all && | ||
141 | t1->src.l3num == t2->src.l3num && | ||
142 | t1->dst.protonum == t2->dst.protonum); | ||
143 | } | ||
144 | |||
145 | static inline int nf_ct_tuple_dst_equal(const struct nf_conntrack_tuple *t1, | ||
146 | const struct nf_conntrack_tuple *t2) | ||
147 | { | ||
148 | return (t1->dst.u3.all[0] == t2->dst.u3.all[0] && | ||
149 | t1->dst.u3.all[1] == t2->dst.u3.all[1] && | ||
150 | t1->dst.u3.all[2] == t2->dst.u3.all[2] && | ||
151 | t1->dst.u3.all[3] == t2->dst.u3.all[3] && | ||
152 | t1->dst.u.all == t2->dst.u.all && | ||
153 | t1->src.l3num == t2->src.l3num && | ||
154 | t1->dst.protonum == t2->dst.protonum); | ||
155 | } | ||
156 | |||
157 | static inline int nf_ct_tuple_equal(const struct nf_conntrack_tuple *t1, | ||
158 | const struct nf_conntrack_tuple *t2) | ||
159 | { | ||
160 | return nf_ct_tuple_src_equal(t1, t2) && nf_ct_tuple_dst_equal(t1, t2); | ||
161 | } | ||
162 | |||
163 | static inline int nf_ct_tuple_mask_cmp(const struct nf_conntrack_tuple *t, | ||
164 | const struct nf_conntrack_tuple *tuple, | ||
165 | const struct nf_conntrack_tuple *mask) | ||
166 | { | ||
167 | int count = 0; | ||
168 | |||
169 | for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){ | ||
170 | if ((t->src.u3.all[count] ^ tuple->src.u3.all[count]) & | ||
171 | mask->src.u3.all[count]) | ||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){ | ||
176 | if ((t->dst.u3.all[count] ^ tuple->dst.u3.all[count]) & | ||
177 | mask->dst.u3.all[count]) | ||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | if ((t->src.u.all ^ tuple->src.u.all) & mask->src.u.all || | ||
182 | (t->dst.u.all ^ tuple->dst.u.all) & mask->dst.u.all || | ||
183 | (t->src.l3num ^ tuple->src.l3num) & mask->src.l3num || | ||
184 | (t->dst.protonum ^ tuple->dst.protonum) & mask->dst.protonum) | ||
185 | return 0; | ||
186 | |||
187 | return 1; | ||
188 | } | ||
189 | |||
190 | #endif /* _NF_CONNTRACK_TUPLE_H */ | ||
diff --git a/include/net/netlink.h b/include/net/netlink.h new file mode 100644 index 000000000000..640c26a90cf1 --- /dev/null +++ b/include/net/netlink.h | |||
@@ -0,0 +1,883 @@ | |||
1 | #ifndef __NET_NETLINK_H | ||
2 | #define __NET_NETLINK_H | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | #include <linux/netlink.h> | ||
6 | |||
7 | /* ======================================================================== | ||
8 | * Netlink Messages and Attributes Interface (As Seen On TV) | ||
9 | * ------------------------------------------------------------------------ | ||
10 | * Messages Interface | ||
11 | * ------------------------------------------------------------------------ | ||
12 | * | ||
13 | * Message Format: | ||
14 | * <--- nlmsg_total_size(payload) ---> | ||
15 | * <-- nlmsg_msg_size(payload) -> | ||
16 | * +----------+- - -+-------------+- - -+-------- - - | ||
17 | * | nlmsghdr | Pad | Payload | Pad | nlmsghdr | ||
18 | * +----------+- - -+-------------+- - -+-------- - - | ||
19 | * nlmsg_data(nlh)---^ ^ | ||
20 | * nlmsg_next(nlh)-----------------------+ | ||
21 | * | ||
22 | * Payload Format: | ||
23 | * <---------------------- nlmsg_len(nlh) ---------------------> | ||
24 | * <------ hdrlen ------> <- nlmsg_attrlen(nlh, hdrlen) -> | ||
25 | * +----------------------+- - -+--------------------------------+ | ||
26 | * | Family Header | Pad | Attributes | | ||
27 | * +----------------------+- - -+--------------------------------+ | ||
28 | * nlmsg_attrdata(nlh, hdrlen)---^ | ||
29 | * | ||
30 | * Data Structures: | ||
31 | * struct nlmsghdr netlink message header | ||
32 | * | ||
33 | * Message Construction: | ||
34 | * nlmsg_new() create a new netlink message | ||
35 | * nlmsg_put() add a netlink message to an skb | ||
36 | * nlmsg_put_answer() callback based nlmsg_put() | ||
37 | * nlmsg_end() finanlize netlink message | ||
38 | * nlmsg_cancel() cancel message construction | ||
39 | * nlmsg_free() free a netlink message | ||
40 | * | ||
41 | * Message Sending: | ||
42 | * nlmsg_multicast() multicast message to several groups | ||
43 | * nlmsg_unicast() unicast a message to a single socket | ||
44 | * | ||
45 | * Message Length Calculations: | ||
46 | * nlmsg_msg_size(payload) length of message w/o padding | ||
47 | * nlmsg_total_size(payload) length of message w/ padding | ||
48 | * nlmsg_padlen(payload) length of padding at tail | ||
49 | * | ||
50 | * Message Payload Access: | ||
51 | * nlmsg_data(nlh) head of message payload | ||
52 | * nlmsg_len(nlh) length of message payload | ||
53 | * nlmsg_attrdata(nlh, hdrlen) head of attributes data | ||
54 | * nlmsg_attrlen(nlh, hdrlen) length of attributes data | ||
55 | * | ||
56 | * Message Parsing: | ||
57 | * nlmsg_ok(nlh, remaining) does nlh fit into remaining bytes? | ||
58 | * nlmsg_next(nlh, remaining) get next netlink message | ||
59 | * nlmsg_parse() parse attributes of a message | ||
60 | * nlmsg_find_attr() find an attribute in a message | ||
61 | * nlmsg_for_each_msg() loop over all messages | ||
62 | * nlmsg_validate() validate netlink message incl. attrs | ||
63 | * nlmsg_for_each_attr() loop over all attributes | ||
64 | * | ||
65 | * ------------------------------------------------------------------------ | ||
66 | * Attributes Interface | ||
67 | * ------------------------------------------------------------------------ | ||
68 | * | ||
69 | * Attribute Format: | ||
70 | * <------- nla_total_size(payload) -------> | ||
71 | * <---- nla_attr_size(payload) -----> | ||
72 | * +----------+- - -+- - - - - - - - - +- - -+-------- - - | ||
73 | * | Header | Pad | Payload | Pad | Header | ||
74 | * +----------+- - -+- - - - - - - - - +- - -+-------- - - | ||
75 | * <- nla_len(nla) -> ^ | ||
76 | * nla_data(nla)----^ | | ||
77 | * nla_next(nla)-----------------------------' | ||
78 | * | ||
79 | * Data Structures: | ||
80 | * struct nlattr netlink attribtue header | ||
81 | * | ||
82 | * Attribute Construction: | ||
83 | * nla_reserve(skb, type, len) reserve skb tailroom for an attribute | ||
84 | * nla_put(skb, type, len, data) add attribute to skb | ||
85 | * | ||
86 | * Attribute Construction for Basic Types: | ||
87 | * nla_put_u8(skb, type, value) add u8 attribute to skb | ||
88 | * nla_put_u16(skb, type, value) add u16 attribute to skb | ||
89 | * nla_put_u32(skb, type, value) add u32 attribute to skb | ||
90 | * nla_put_u64(skb, type, value) add u64 attribute to skb | ||
91 | * nla_put_string(skb, type, str) add string attribute to skb | ||
92 | * nla_put_flag(skb, type) add flag attribute to skb | ||
93 | * nla_put_msecs(skb, type, jiffies) add msecs attribute to skb | ||
94 | * | ||
95 | * Exceptions Based Attribute Construction: | ||
96 | * NLA_PUT(skb, type, len, data) add attribute to skb | ||
97 | * NLA_PUT_U8(skb, type, value) add u8 attribute to skb | ||
98 | * NLA_PUT_U16(skb, type, value) add u16 attribute to skb | ||
99 | * NLA_PUT_U32(skb, type, value) add u32 attribute to skb | ||
100 | * NLA_PUT_U64(skb, type, value) add u64 attribute to skb | ||
101 | * NLA_PUT_STRING(skb, type, str) add string attribute to skb | ||
102 | * NLA_PUT_FLAG(skb, type) add flag attribute to skb | ||
103 | * NLA_PUT_MSECS(skb, type, jiffies) add msecs attribute to skb | ||
104 | * | ||
105 | * The meaning of these functions is equal to their lower case | ||
106 | * variants but they jump to the label nla_put_failure in case | ||
107 | * of a failure. | ||
108 | * | ||
109 | * Nested Attributes Construction: | ||
110 | * nla_nest_start(skb, type) start a nested attribute | ||
111 | * nla_nest_end(skb, nla) finalize a nested attribute | ||
112 | * nla_nest_cancel(skb, nla) cancel nested attribute construction | ||
113 | * | ||
114 | * Attribute Length Calculations: | ||
115 | * nla_attr_size(payload) length of attribute w/o padding | ||
116 | * nla_total_size(payload) length of attribute w/ padding | ||
117 | * nla_padlen(payload) length of padding | ||
118 | * | ||
119 | * Attribute Payload Access: | ||
120 | * nla_data(nla) head of attribute payload | ||
121 | * nla_len(nla) length of attribute payload | ||
122 | * | ||
123 | * Attribute Payload Access for Basic Types: | ||
124 | * nla_get_u8(nla) get payload for a u8 attribute | ||
125 | * nla_get_u16(nla) get payload for a u16 attribute | ||
126 | * nla_get_u32(nla) get payload for a u32 attribute | ||
127 | * nla_get_u64(nla) get payload for a u64 attribute | ||
128 | * nla_get_flag(nla) return 1 if flag is true | ||
129 | * nla_get_msecs(nla) get payload for a msecs attribute | ||
130 | * | ||
131 | * Attribute Misc: | ||
132 | * nla_memcpy(dest, nla, count) copy attribute into memory | ||
133 | * nla_memcmp(nla, data, size) compare attribute with memory area | ||
134 | * nla_strlcpy(dst, nla, size) copy attribute to a sized string | ||
135 | * nla_strcmp(nla, str) compare attribute with string | ||
136 | * | ||
137 | * Attribute Parsing: | ||
138 | * nla_ok(nla, remaining) does nla fit into remaining bytes? | ||
139 | * nla_next(nla, remaining) get next netlink attribute | ||
140 | * nla_validate() validate a stream of attributes | ||
141 | * nla_find() find attribute in stream of attributes | ||
142 | * nla_parse() parse and validate stream of attrs | ||
143 | * nla_parse_nested() parse nested attribuets | ||
144 | * nla_for_each_attr() loop over all attributes | ||
145 | *========================================================================= | ||
146 | */ | ||
147 | |||
148 | /** | ||
149 | * Standard attribute types to specify validation policy | ||
150 | */ | ||
151 | enum { | ||
152 | NLA_UNSPEC, | ||
153 | NLA_U8, | ||
154 | NLA_U16, | ||
155 | NLA_U32, | ||
156 | NLA_U64, | ||
157 | NLA_STRING, | ||
158 | NLA_FLAG, | ||
159 | NLA_MSECS, | ||
160 | NLA_NESTED, | ||
161 | __NLA_TYPE_MAX, | ||
162 | }; | ||
163 | |||
164 | #define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1) | ||
165 | |||
166 | /** | ||
167 | * struct nla_policy - attribute validation policy | ||
168 | * @type: Type of attribute or NLA_UNSPEC | ||
169 | * @minlen: Minimal length of payload required to be available | ||
170 | * | ||
171 | * Policies are defined as arrays of this struct, the array must be | ||
172 | * accessible by attribute type up to the highest identifier to be expected. | ||
173 | * | ||
174 | * Example: | ||
175 | * static struct nla_policy my_policy[ATTR_MAX+1] __read_mostly = { | ||
176 | * [ATTR_FOO] = { .type = NLA_U16 }, | ||
177 | * [ATTR_BAR] = { .type = NLA_STRING }, | ||
178 | * [ATTR_BAZ] = { .minlen = sizeof(struct mystruct) }, | ||
179 | * }; | ||
180 | */ | ||
181 | struct nla_policy { | ||
182 | u16 type; | ||
183 | u16 minlen; | ||
184 | }; | ||
185 | |||
186 | extern void netlink_run_queue(struct sock *sk, unsigned int *qlen, | ||
187 | int (*cb)(struct sk_buff *, | ||
188 | struct nlmsghdr *, int *)); | ||
189 | extern void netlink_queue_skip(struct nlmsghdr *nlh, | ||
190 | struct sk_buff *skb); | ||
191 | |||
192 | extern int nla_validate(struct nlattr *head, int len, int maxtype, | ||
193 | struct nla_policy *policy); | ||
194 | extern int nla_parse(struct nlattr *tb[], int maxtype, | ||
195 | struct nlattr *head, int len, | ||
196 | struct nla_policy *policy); | ||
197 | extern struct nlattr * nla_find(struct nlattr *head, int len, int attrtype); | ||
198 | extern size_t nla_strlcpy(char *dst, const struct nlattr *nla, | ||
199 | size_t dstsize); | ||
200 | extern int nla_memcpy(void *dest, struct nlattr *src, int count); | ||
201 | extern int nla_memcmp(const struct nlattr *nla, const void *data, | ||
202 | size_t size); | ||
203 | extern int nla_strcmp(const struct nlattr *nla, const char *str); | ||
204 | extern struct nlattr * __nla_reserve(struct sk_buff *skb, int attrtype, | ||
205 | int attrlen); | ||
206 | extern struct nlattr * nla_reserve(struct sk_buff *skb, int attrtype, | ||
207 | int attrlen); | ||
208 | extern void __nla_put(struct sk_buff *skb, int attrtype, | ||
209 | int attrlen, const void *data); | ||
210 | extern int nla_put(struct sk_buff *skb, int attrtype, | ||
211 | int attrlen, const void *data); | ||
212 | |||
213 | /************************************************************************** | ||
214 | * Netlink Messages | ||
215 | **************************************************************************/ | ||
216 | |||
217 | /** | ||
218 | * nlmsg_msg_size - length of netlink message not including padding | ||
219 | * @payload: length of message payload | ||
220 | */ | ||
221 | static inline int nlmsg_msg_size(int payload) | ||
222 | { | ||
223 | return NLMSG_HDRLEN + payload; | ||
224 | } | ||
225 | |||
226 | /** | ||
227 | * nlmsg_total_size - length of netlink message including padding | ||
228 | * @payload: length of message payload | ||
229 | */ | ||
230 | static inline int nlmsg_total_size(int payload) | ||
231 | { | ||
232 | return NLMSG_ALIGN(nlmsg_msg_size(payload)); | ||
233 | } | ||
234 | |||
235 | /** | ||
236 | * nlmsg_padlen - length of padding at the message's tail | ||
237 | * @payload: length of message payload | ||
238 | */ | ||
239 | static inline int nlmsg_padlen(int payload) | ||
240 | { | ||
241 | return nlmsg_total_size(payload) - nlmsg_msg_size(payload); | ||
242 | } | ||
243 | |||
244 | /** | ||
245 | * nlmsg_data - head of message payload | ||
246 | * @nlh: netlink messsage header | ||
247 | */ | ||
248 | static inline void *nlmsg_data(const struct nlmsghdr *nlh) | ||
249 | { | ||
250 | return (unsigned char *) nlh + NLMSG_HDRLEN; | ||
251 | } | ||
252 | |||
253 | /** | ||
254 | * nlmsg_len - length of message payload | ||
255 | * @nlh: netlink message header | ||
256 | */ | ||
257 | static inline int nlmsg_len(const struct nlmsghdr *nlh) | ||
258 | { | ||
259 | return nlh->nlmsg_len - NLMSG_HDRLEN; | ||
260 | } | ||
261 | |||
262 | /** | ||
263 | * nlmsg_attrdata - head of attributes data | ||
264 | * @nlh: netlink message header | ||
265 | * @hdrlen: length of family specific header | ||
266 | */ | ||
267 | static inline struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, | ||
268 | int hdrlen) | ||
269 | { | ||
270 | unsigned char *data = nlmsg_data(nlh); | ||
271 | return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen)); | ||
272 | } | ||
273 | |||
274 | /** | ||
275 | * nlmsg_attrlen - length of attributes data | ||
276 | * @nlh: netlink message header | ||
277 | * @hdrlen: length of family specific header | ||
278 | */ | ||
279 | static inline int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen) | ||
280 | { | ||
281 | return nlmsg_len(nlh) - NLMSG_ALIGN(hdrlen); | ||
282 | } | ||
283 | |||
284 | /** | ||
285 | * nlmsg_ok - check if the netlink message fits into the remaining bytes | ||
286 | * @nlh: netlink message header | ||
287 | * @remaining: number of bytes remaining in message stream | ||
288 | */ | ||
289 | static inline int nlmsg_ok(const struct nlmsghdr *nlh, int remaining) | ||
290 | { | ||
291 | return (remaining >= sizeof(struct nlmsghdr) && | ||
292 | nlh->nlmsg_len >= sizeof(struct nlmsghdr) && | ||
293 | nlh->nlmsg_len <= remaining); | ||
294 | } | ||
295 | |||
296 | /** | ||
297 | * nlmsg_next - next netlink message in message stream | ||
298 | * @nlh: netlink message header | ||
299 | * @remaining: number of bytes remaining in message stream | ||
300 | * | ||
301 | * Returns the next netlink message in the message stream and | ||
302 | * decrements remaining by the size of the current message. | ||
303 | */ | ||
304 | static inline struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining) | ||
305 | { | ||
306 | int totlen = NLMSG_ALIGN(nlh->nlmsg_len); | ||
307 | |||
308 | *remaining -= totlen; | ||
309 | |||
310 | return (struct nlmsghdr *) ((unsigned char *) nlh + totlen); | ||
311 | } | ||
312 | |||
313 | /** | ||
314 | * nlmsg_parse - parse attributes of a netlink message | ||
315 | * @nlh: netlink message header | ||
316 | * @hdrlen: length of family specific header | ||
317 | * @tb: destination array with maxtype+1 elements | ||
318 | * @maxtype: maximum attribute type to be expected | ||
319 | * @policy: validation policy | ||
320 | * | ||
321 | * See nla_parse() | ||
322 | */ | ||
323 | static inline int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, | ||
324 | struct nlattr *tb[], int maxtype, | ||
325 | struct nla_policy *policy) | ||
326 | { | ||
327 | if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) | ||
328 | return -EINVAL; | ||
329 | |||
330 | return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen), | ||
331 | nlmsg_attrlen(nlh, hdrlen), policy); | ||
332 | } | ||
333 | |||
334 | /** | ||
335 | * nlmsg_find_attr - find a specific attribute in a netlink message | ||
336 | * @nlh: netlink message header | ||
337 | * @hdrlen: length of familiy specific header | ||
338 | * @attrtype: type of attribute to look for | ||
339 | * | ||
340 | * Returns the first attribute which matches the specified type. | ||
341 | */ | ||
342 | static inline struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh, | ||
343 | int hdrlen, int attrtype) | ||
344 | { | ||
345 | return nla_find(nlmsg_attrdata(nlh, hdrlen), | ||
346 | nlmsg_attrlen(nlh, hdrlen), attrtype); | ||
347 | } | ||
348 | |||
349 | /** | ||
350 | * nlmsg_validate - validate a netlink message including attributes | ||
351 | * @nlh: netlinket message header | ||
352 | * @hdrlen: length of familiy specific header | ||
353 | * @maxtype: maximum attribute type to be expected | ||
354 | * @policy: validation policy | ||
355 | */ | ||
356 | static inline int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype, | ||
357 | struct nla_policy *policy) | ||
358 | { | ||
359 | if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) | ||
360 | return -EINVAL; | ||
361 | |||
362 | return nla_validate(nlmsg_attrdata(nlh, hdrlen), | ||
363 | nlmsg_attrlen(nlh, hdrlen), maxtype, policy); | ||
364 | } | ||
365 | |||
366 | /** | ||
367 | * nlmsg_for_each_attr - iterate over a stream of attributes | ||
368 | * @pos: loop counter, set to current attribute | ||
369 | * @nlh: netlink message header | ||
370 | * @hdrlen: length of familiy specific header | ||
371 | * @rem: initialized to len, holds bytes currently remaining in stream | ||
372 | */ | ||
373 | #define nlmsg_for_each_attr(pos, nlh, hdrlen, rem) \ | ||
374 | nla_for_each_attr(pos, nlmsg_attrdata(nlh, hdrlen), \ | ||
375 | nlmsg_attrlen(nlh, hdrlen), rem) | ||
376 | |||
377 | #if 0 | ||
378 | /* FIXME: Enable once all users have been converted */ | ||
379 | |||
380 | /** | ||
381 | * __nlmsg_put - Add a new netlink message to an skb | ||
382 | * @skb: socket buffer to store message in | ||
383 | * @pid: netlink process id | ||
384 | * @seq: sequence number of message | ||
385 | * @type: message type | ||
386 | * @payload: length of message payload | ||
387 | * @flags: message flags | ||
388 | * | ||
389 | * The caller is responsible to ensure that the skb provides enough | ||
390 | * tailroom for both the netlink header and payload. | ||
391 | */ | ||
392 | static inline struct nlmsghdr *__nlmsg_put(struct sk_buff *skb, u32 pid, | ||
393 | u32 seq, int type, int payload, | ||
394 | int flags) | ||
395 | { | ||
396 | struct nlmsghdr *nlh; | ||
397 | |||
398 | nlh = (struct nlmsghdr *) skb_put(skb, nlmsg_total_size(payload)); | ||
399 | nlh->nlmsg_type = type; | ||
400 | nlh->nlmsg_len = nlmsg_msg_size(payload); | ||
401 | nlh->nlmsg_flags = flags; | ||
402 | nlh->nlmsg_pid = pid; | ||
403 | nlh->nlmsg_seq = seq; | ||
404 | |||
405 | memset((unsigned char *) nlmsg_data(nlh) + payload, 0, | ||
406 | nlmsg_padlen(payload)); | ||
407 | |||
408 | return nlh; | ||
409 | } | ||
410 | #endif | ||
411 | |||
412 | /** | ||
413 | * nlmsg_put - Add a new netlink message to an skb | ||
414 | * @skb: socket buffer to store message in | ||
415 | * @pid: netlink process id | ||
416 | * @seq: sequence number of message | ||
417 | * @type: message type | ||
418 | * @payload: length of message payload | ||
419 | * @flags: message flags | ||
420 | * | ||
421 | * Returns NULL if the tailroom of the skb is insufficient to store | ||
422 | * the message header and payload. | ||
423 | */ | ||
424 | static inline struct nlmsghdr *nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, | ||
425 | int type, int payload, int flags) | ||
426 | { | ||
427 | if (unlikely(skb_tailroom(skb) < nlmsg_total_size(payload))) | ||
428 | return NULL; | ||
429 | |||
430 | return __nlmsg_put(skb, pid, seq, type, payload, flags); | ||
431 | } | ||
432 | |||
433 | /** | ||
434 | * nlmsg_put_answer - Add a new callback based netlink message to an skb | ||
435 | * @skb: socket buffer to store message in | ||
436 | * @cb: netlink callback | ||
437 | * @type: message type | ||
438 | * @payload: length of message payload | ||
439 | * @flags: message flags | ||
440 | * | ||
441 | * Returns NULL if the tailroom of the skb is insufficient to store | ||
442 | * the message header and payload. | ||
443 | */ | ||
444 | static inline struct nlmsghdr *nlmsg_put_answer(struct sk_buff *skb, | ||
445 | struct netlink_callback *cb, | ||
446 | int type, int payload, | ||
447 | int flags) | ||
448 | { | ||
449 | return nlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, | ||
450 | type, payload, flags); | ||
451 | } | ||
452 | |||
453 | /** | ||
454 | * nlmsg_new - Allocate a new netlink message | ||
455 | * @size: maximum size of message | ||
456 | * | ||
457 | * Use NLMSG_GOODSIZE if size isn't know and you need a good default size. | ||
458 | */ | ||
459 | static inline struct sk_buff *nlmsg_new(int size) | ||
460 | { | ||
461 | return alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | ||
462 | } | ||
463 | |||
464 | /** | ||
465 | * nlmsg_end - Finalize a netlink message | ||
466 | * @skb: socket buffer the message is stored in | ||
467 | * @nlh: netlink message header | ||
468 | * | ||
469 | * Corrects the netlink message header to include the appeneded | ||
470 | * attributes. Only necessary if attributes have been added to | ||
471 | * the message. | ||
472 | * | ||
473 | * Returns the total data length of the skb. | ||
474 | */ | ||
475 | static inline int nlmsg_end(struct sk_buff *skb, struct nlmsghdr *nlh) | ||
476 | { | ||
477 | nlh->nlmsg_len = skb->tail - (unsigned char *) nlh; | ||
478 | |||
479 | return skb->len; | ||
480 | } | ||
481 | |||
482 | /** | ||
483 | * nlmsg_cancel - Cancel construction of a netlink message | ||
484 | * @skb: socket buffer the message is stored in | ||
485 | * @nlh: netlink message header | ||
486 | * | ||
487 | * Removes the complete netlink message including all | ||
488 | * attributes from the socket buffer again. Returns -1. | ||
489 | */ | ||
490 | static inline int nlmsg_cancel(struct sk_buff *skb, struct nlmsghdr *nlh) | ||
491 | { | ||
492 | skb_trim(skb, (unsigned char *) nlh - skb->data); | ||
493 | |||
494 | return -1; | ||
495 | } | ||
496 | |||
497 | /** | ||
498 | * nlmsg_free - free a netlink message | ||
499 | * @skb: socket buffer of netlink message | ||
500 | */ | ||
501 | static inline void nlmsg_free(struct sk_buff *skb) | ||
502 | { | ||
503 | kfree_skb(skb); | ||
504 | } | ||
505 | |||
506 | /** | ||
507 | * nlmsg_multicast - multicast a netlink message | ||
508 | * @sk: netlink socket to spread messages to | ||
509 | * @skb: netlink message as socket buffer | ||
510 | * @pid: own netlink pid to avoid sending to yourself | ||
511 | * @group: multicast group id | ||
512 | */ | ||
513 | static inline int nlmsg_multicast(struct sock *sk, struct sk_buff *skb, | ||
514 | u32 pid, unsigned int group) | ||
515 | { | ||
516 | int err; | ||
517 | |||
518 | NETLINK_CB(skb).dst_group = group; | ||
519 | |||
520 | err = netlink_broadcast(sk, skb, pid, group, GFP_KERNEL); | ||
521 | if (err > 0) | ||
522 | err = 0; | ||
523 | |||
524 | return err; | ||
525 | } | ||
526 | |||
527 | /** | ||
528 | * nlmsg_unicast - unicast a netlink message | ||
529 | * @sk: netlink socket to spread message to | ||
530 | * @skb: netlink message as socket buffer | ||
531 | * @pid: netlink pid of the destination socket | ||
532 | */ | ||
533 | static inline int nlmsg_unicast(struct sock *sk, struct sk_buff *skb, u32 pid) | ||
534 | { | ||
535 | int err; | ||
536 | |||
537 | err = netlink_unicast(sk, skb, pid, MSG_DONTWAIT); | ||
538 | if (err > 0) | ||
539 | err = 0; | ||
540 | |||
541 | return err; | ||
542 | } | ||
543 | |||
544 | /** | ||
545 | * nlmsg_for_each_msg - iterate over a stream of messages | ||
546 | * @pos: loop counter, set to current message | ||
547 | * @head: head of message stream | ||
548 | * @len: length of message stream | ||
549 | * @rem: initialized to len, holds bytes currently remaining in stream | ||
550 | */ | ||
551 | #define nlmsg_for_each_msg(pos, head, len, rem) \ | ||
552 | for (pos = head, rem = len; \ | ||
553 | nlmsg_ok(pos, rem); \ | ||
554 | pos = nlmsg_next(pos, &(rem))) | ||
555 | |||
556 | /************************************************************************** | ||
557 | * Netlink Attributes | ||
558 | **************************************************************************/ | ||
559 | |||
560 | /** | ||
561 | * nla_attr_size - length of attribute not including padding | ||
562 | * @payload: length of payload | ||
563 | */ | ||
564 | static inline int nla_attr_size(int payload) | ||
565 | { | ||
566 | return NLA_HDRLEN + payload; | ||
567 | } | ||
568 | |||
569 | /** | ||
570 | * nla_total_size - total length of attribute including padding | ||
571 | * @payload: length of payload | ||
572 | */ | ||
573 | static inline int nla_total_size(int payload) | ||
574 | { | ||
575 | return NLA_ALIGN(nla_attr_size(payload)); | ||
576 | } | ||
577 | |||
578 | /** | ||
579 | * nla_padlen - length of padding at the tail of attribute | ||
580 | * @payload: length of payload | ||
581 | */ | ||
582 | static inline int nla_padlen(int payload) | ||
583 | { | ||
584 | return nla_total_size(payload) - nla_attr_size(payload); | ||
585 | } | ||
586 | |||
587 | /** | ||
588 | * nla_data - head of payload | ||
589 | * @nla: netlink attribute | ||
590 | */ | ||
591 | static inline void *nla_data(const struct nlattr *nla) | ||
592 | { | ||
593 | return (char *) nla + NLA_HDRLEN; | ||
594 | } | ||
595 | |||
596 | /** | ||
597 | * nla_len - length of payload | ||
598 | * @nla: netlink attribute | ||
599 | */ | ||
600 | static inline int nla_len(const struct nlattr *nla) | ||
601 | { | ||
602 | return nla->nla_len - NLA_HDRLEN; | ||
603 | } | ||
604 | |||
605 | /** | ||
606 | * nla_ok - check if the netlink attribute fits into the remaining bytes | ||
607 | * @nla: netlink attribute | ||
608 | * @remaining: number of bytes remaining in attribute stream | ||
609 | */ | ||
610 | static inline int nla_ok(const struct nlattr *nla, int remaining) | ||
611 | { | ||
612 | return remaining >= sizeof(*nla) && | ||
613 | nla->nla_len >= sizeof(*nla) && | ||
614 | nla->nla_len <= remaining; | ||
615 | } | ||
616 | |||
617 | /** | ||
618 | * nla_next - next netlink attribte in attribute stream | ||
619 | * @nla: netlink attribute | ||
620 | * @remaining: number of bytes remaining in attribute stream | ||
621 | * | ||
622 | * Returns the next netlink attribute in the attribute stream and | ||
623 | * decrements remaining by the size of the current attribute. | ||
624 | */ | ||
625 | static inline struct nlattr *nla_next(const struct nlattr *nla, int *remaining) | ||
626 | { | ||
627 | int totlen = NLA_ALIGN(nla->nla_len); | ||
628 | |||
629 | *remaining -= totlen; | ||
630 | return (struct nlattr *) ((char *) nla + totlen); | ||
631 | } | ||
632 | |||
633 | /** | ||
634 | * nla_parse_nested - parse nested attributes | ||
635 | * @tb: destination array with maxtype+1 elements | ||
636 | * @maxtype: maximum attribute type to be expected | ||
637 | * @nla: attribute containing the nested attributes | ||
638 | * @policy: validation policy | ||
639 | * | ||
640 | * See nla_parse() | ||
641 | */ | ||
642 | static inline int nla_parse_nested(struct nlattr *tb[], int maxtype, | ||
643 | struct nlattr *nla, | ||
644 | struct nla_policy *policy) | ||
645 | { | ||
646 | return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy); | ||
647 | } | ||
648 | /** | ||
649 | * nla_put_u8 - Add a u16 netlink attribute to a socket buffer | ||
650 | * @skb: socket buffer to add attribute to | ||
651 | * @attrtype: attribute type | ||
652 | * @value: numeric value | ||
653 | */ | ||
654 | static inline int nla_put_u8(struct sk_buff *skb, int attrtype, u8 value) | ||
655 | { | ||
656 | return nla_put(skb, attrtype, sizeof(u8), &value); | ||
657 | } | ||
658 | |||
659 | /** | ||
660 | * nla_put_u16 - Add a u16 netlink attribute to a socket buffer | ||
661 | * @skb: socket buffer to add attribute to | ||
662 | * @attrtype: attribute type | ||
663 | * @value: numeric value | ||
664 | */ | ||
665 | static inline int nla_put_u16(struct sk_buff *skb, int attrtype, u16 value) | ||
666 | { | ||
667 | return nla_put(skb, attrtype, sizeof(u16), &value); | ||
668 | } | ||
669 | |||
670 | /** | ||
671 | * nla_put_u32 - Add a u32 netlink attribute to a socket buffer | ||
672 | * @skb: socket buffer to add attribute to | ||
673 | * @attrtype: attribute type | ||
674 | * @value: numeric value | ||
675 | */ | ||
676 | static inline int nla_put_u32(struct sk_buff *skb, int attrtype, u32 value) | ||
677 | { | ||
678 | return nla_put(skb, attrtype, sizeof(u32), &value); | ||
679 | } | ||
680 | |||
681 | /** | ||
682 | * nla_put_64 - Add a u64 netlink attribute to a socket buffer | ||
683 | * @skb: socket buffer to add attribute to | ||
684 | * @attrtype: attribute type | ||
685 | * @value: numeric value | ||
686 | */ | ||
687 | static inline int nla_put_u64(struct sk_buff *skb, int attrtype, u64 value) | ||
688 | { | ||
689 | return nla_put(skb, attrtype, sizeof(u64), &value); | ||
690 | } | ||
691 | |||
692 | /** | ||
693 | * nla_put_string - Add a string netlink attribute to a socket buffer | ||
694 | * @skb: socket buffer to add attribute to | ||
695 | * @attrtype: attribute type | ||
696 | * @str: NUL terminated string | ||
697 | */ | ||
698 | static inline int nla_put_string(struct sk_buff *skb, int attrtype, | ||
699 | const char *str) | ||
700 | { | ||
701 | return nla_put(skb, attrtype, strlen(str) + 1, str); | ||
702 | } | ||
703 | |||
704 | /** | ||
705 | * nla_put_flag - Add a flag netlink attribute to a socket buffer | ||
706 | * @skb: socket buffer to add attribute to | ||
707 | * @attrtype: attribute type | ||
708 | */ | ||
709 | static inline int nla_put_flag(struct sk_buff *skb, int attrtype) | ||
710 | { | ||
711 | return nla_put(skb, attrtype, 0, NULL); | ||
712 | } | ||
713 | |||
714 | /** | ||
715 | * nla_put_msecs - Add a msecs netlink attribute to a socket buffer | ||
716 | * @skb: socket buffer to add attribute to | ||
717 | * @attrtype: attribute type | ||
718 | * @jiffies: number of msecs in jiffies | ||
719 | */ | ||
720 | static inline int nla_put_msecs(struct sk_buff *skb, int attrtype, | ||
721 | unsigned long jiffies) | ||
722 | { | ||
723 | u64 tmp = jiffies_to_msecs(jiffies); | ||
724 | return nla_put(skb, attrtype, sizeof(u64), &tmp); | ||
725 | } | ||
726 | |||
727 | #define NLA_PUT(skb, attrtype, attrlen, data) \ | ||
728 | do { \ | ||
729 | if (nla_put(skb, attrtype, attrlen, data) < 0) \ | ||
730 | goto nla_put_failure; \ | ||
731 | } while(0) | ||
732 | |||
733 | #define NLA_PUT_TYPE(skb, type, attrtype, value) \ | ||
734 | do { \ | ||
735 | type __tmp = value; \ | ||
736 | NLA_PUT(skb, attrtype, sizeof(type), &__tmp); \ | ||
737 | } while(0) | ||
738 | |||
739 | #define NLA_PUT_U8(skb, attrtype, value) \ | ||
740 | NLA_PUT_TYPE(skb, u8, attrtype, value) | ||
741 | |||
742 | #define NLA_PUT_U16(skb, attrtype, value) \ | ||
743 | NLA_PUT_TYPE(skb, u16, attrtype, value) | ||
744 | |||
745 | #define NLA_PUT_U32(skb, attrtype, value) \ | ||
746 | NLA_PUT_TYPE(skb, u32, attrtype, value) | ||
747 | |||
748 | #define NLA_PUT_U64(skb, attrtype, value) \ | ||
749 | NLA_PUT_TYPE(skb, u64, attrtype, value) | ||
750 | |||
751 | #define NLA_PUT_STRING(skb, attrtype, value) \ | ||
752 | NLA_PUT(skb, attrtype, strlen(value) + 1, value) | ||
753 | |||
754 | #define NLA_PUT_FLAG(skb, attrtype, value) \ | ||
755 | NLA_PUT(skb, attrtype, 0, NULL) | ||
756 | |||
757 | #define NLA_PUT_MSECS(skb, attrtype, jiffies) \ | ||
758 | NLA_PUT_U64(skb, attrtype, jiffies_to_msecs(jiffies)) | ||
759 | |||
760 | /** | ||
761 | * nla_get_u32 - return payload of u32 attribute | ||
762 | * @nla: u32 netlink attribute | ||
763 | */ | ||
764 | static inline u32 nla_get_u32(struct nlattr *nla) | ||
765 | { | ||
766 | return *(u32 *) nla_data(nla); | ||
767 | } | ||
768 | |||
769 | /** | ||
770 | * nla_get_u16 - return payload of u16 attribute | ||
771 | * @nla: u16 netlink attribute | ||
772 | */ | ||
773 | static inline u16 nla_get_u16(struct nlattr *nla) | ||
774 | { | ||
775 | return *(u16 *) nla_data(nla); | ||
776 | } | ||
777 | |||
778 | /** | ||
779 | * nla_get_u8 - return payload of u8 attribute | ||
780 | * @nla: u8 netlink attribute | ||
781 | */ | ||
782 | static inline u8 nla_get_u8(struct nlattr *nla) | ||
783 | { | ||
784 | return *(u8 *) nla_data(nla); | ||
785 | } | ||
786 | |||
787 | /** | ||
788 | * nla_get_u64 - return payload of u64 attribute | ||
789 | * @nla: u64 netlink attribute | ||
790 | */ | ||
791 | static inline u64 nla_get_u64(struct nlattr *nla) | ||
792 | { | ||
793 | u64 tmp; | ||
794 | |||
795 | nla_memcpy(&tmp, nla, sizeof(tmp)); | ||
796 | |||
797 | return tmp; | ||
798 | } | ||
799 | |||
800 | /** | ||
801 | * nla_get_flag - return payload of flag attribute | ||
802 | * @nla: flag netlink attribute | ||
803 | */ | ||
804 | static inline int nla_get_flag(struct nlattr *nla) | ||
805 | { | ||
806 | return !!nla; | ||
807 | } | ||
808 | |||
809 | /** | ||
810 | * nla_get_msecs - return payload of msecs attribute | ||
811 | * @nla: msecs netlink attribute | ||
812 | * | ||
813 | * Returns the number of milliseconds in jiffies. | ||
814 | */ | ||
815 | static inline unsigned long nla_get_msecs(struct nlattr *nla) | ||
816 | { | ||
817 | u64 msecs = nla_get_u64(nla); | ||
818 | |||
819 | return msecs_to_jiffies((unsigned long) msecs); | ||
820 | } | ||
821 | |||
822 | /** | ||
823 | * nla_nest_start - Start a new level of nested attributes | ||
824 | * @skb: socket buffer to add attributes to | ||
825 | * @attrtype: attribute type of container | ||
826 | * | ||
827 | * Returns the container attribute | ||
828 | */ | ||
829 | static inline struct nlattr *nla_nest_start(struct sk_buff *skb, int attrtype) | ||
830 | { | ||
831 | struct nlattr *start = (struct nlattr *) skb->tail; | ||
832 | |||
833 | if (nla_put(skb, attrtype, 0, NULL) < 0) | ||
834 | return NULL; | ||
835 | |||
836 | return start; | ||
837 | } | ||
838 | |||
839 | /** | ||
840 | * nla_nest_end - Finalize nesting of attributes | ||
841 | * @skb: socket buffer the attribtues are stored in | ||
842 | * @start: container attribute | ||
843 | * | ||
844 | * Corrects the container attribute header to include the all | ||
845 | * appeneded attributes. | ||
846 | * | ||
847 | * Returns the total data length of the skb. | ||
848 | */ | ||
849 | static inline int nla_nest_end(struct sk_buff *skb, struct nlattr *start) | ||
850 | { | ||
851 | start->nla_len = skb->tail - (unsigned char *) start; | ||
852 | return skb->len; | ||
853 | } | ||
854 | |||
855 | /** | ||
856 | * nla_nest_cancel - Cancel nesting of attributes | ||
857 | * @skb: socket buffer the message is stored in | ||
858 | * @start: container attribute | ||
859 | * | ||
860 | * Removes the container attribute and including all nested | ||
861 | * attributes. Returns -1. | ||
862 | */ | ||
863 | static inline int nla_nest_cancel(struct sk_buff *skb, struct nlattr *start) | ||
864 | { | ||
865 | if (start) | ||
866 | skb_trim(skb, (unsigned char *) start - skb->data); | ||
867 | |||
868 | return -1; | ||
869 | } | ||
870 | |||
871 | /** | ||
872 | * nla_for_each_attr - iterate over a stream of attributes | ||
873 | * @pos: loop counter, set to current attribute | ||
874 | * @head: head of attribute stream | ||
875 | * @len: length of attribute stream | ||
876 | * @rem: initialized to len, holds bytes currently remaining in stream | ||
877 | */ | ||
878 | #define nla_for_each_attr(pos, head, len, rem) \ | ||
879 | for (pos = head, rem = len; \ | ||
880 | nla_ok(pos, rem); \ | ||
881 | pos = nla_next(pos, &(rem))) | ||
882 | |||
883 | #endif | ||
diff --git a/include/net/tcp.h b/include/net/tcp.h index c24339c4e310..96cc3b434e40 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/cache.h> | 28 | #include <linux/cache.h> |
29 | #include <linux/percpu.h> | 29 | #include <linux/percpu.h> |
30 | #include <linux/skbuff.h> | ||
30 | 31 | ||
31 | #include <net/inet_connection_sock.h> | 32 | #include <net/inet_connection_sock.h> |
32 | #include <net/inet_timewait_sock.h> | 33 | #include <net/inet_timewait_sock.h> |
@@ -852,7 +853,7 @@ static __inline__ u16 tcp_v4_check(struct tcphdr *th, int len, | |||
852 | 853 | ||
853 | static __inline__ int __tcp_checksum_complete(struct sk_buff *skb) | 854 | static __inline__ int __tcp_checksum_complete(struct sk_buff *skb) |
854 | { | 855 | { |
855 | return (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)); | 856 | return __skb_checksum_complete(skb); |
856 | } | 857 | } |
857 | 858 | ||
858 | static __inline__ int tcp_checksum_complete(struct sk_buff *skb) | 859 | static __inline__ int tcp_checksum_complete(struct sk_buff *skb) |
diff --git a/include/rdma/ib_user_verbs.h b/include/rdma/ib_user_verbs.h index 072f3a2edace..5ff1490c08db 100644 --- a/include/rdma/ib_user_verbs.h +++ b/include/rdma/ib_user_verbs.h | |||
@@ -43,7 +43,7 @@ | |||
43 | * Increment this value if any changes that break userspace ABI | 43 | * Increment this value if any changes that break userspace ABI |
44 | * compatibility are made. | 44 | * compatibility are made. |
45 | */ | 45 | */ |
46 | #define IB_USER_VERBS_ABI_VERSION 3 | 46 | #define IB_USER_VERBS_ABI_VERSION 4 |
47 | 47 | ||
48 | enum { | 48 | enum { |
49 | IB_USER_VERBS_CMD_GET_CONTEXT, | 49 | IB_USER_VERBS_CMD_GET_CONTEXT, |
@@ -333,6 +333,11 @@ struct ib_uverbs_create_qp { | |||
333 | struct ib_uverbs_create_qp_resp { | 333 | struct ib_uverbs_create_qp_resp { |
334 | __u32 qp_handle; | 334 | __u32 qp_handle; |
335 | __u32 qpn; | 335 | __u32 qpn; |
336 | __u32 max_send_wr; | ||
337 | __u32 max_recv_wr; | ||
338 | __u32 max_send_sge; | ||
339 | __u32 max_recv_sge; | ||
340 | __u32 max_inline_data; | ||
336 | }; | 341 | }; |
337 | 342 | ||
338 | /* | 343 | /* |
@@ -552,9 +557,7 @@ struct ib_uverbs_modify_srq { | |||
552 | __u32 srq_handle; | 557 | __u32 srq_handle; |
553 | __u32 attr_mask; | 558 | __u32 attr_mask; |
554 | __u32 max_wr; | 559 | __u32 max_wr; |
555 | __u32 max_sge; | ||
556 | __u32 srq_limit; | 560 | __u32 srq_limit; |
557 | __u32 reserved; | ||
558 | __u64 driver_data[0]; | 561 | __u64 driver_data[0]; |
559 | }; | 562 | }; |
560 | 563 | ||
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index f72d46d54e0a..a7f4c355a91f 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h | |||
@@ -881,7 +881,7 @@ struct ib_device { | |||
881 | struct ib_ucontext *context, | 881 | struct ib_ucontext *context, |
882 | struct ib_udata *udata); | 882 | struct ib_udata *udata); |
883 | int (*destroy_cq)(struct ib_cq *cq); | 883 | int (*destroy_cq)(struct ib_cq *cq); |
884 | int (*resize_cq)(struct ib_cq *cq, int *cqe); | 884 | int (*resize_cq)(struct ib_cq *cq, int cqe); |
885 | int (*poll_cq)(struct ib_cq *cq, int num_entries, | 885 | int (*poll_cq)(struct ib_cq *cq, int num_entries, |
886 | struct ib_wc *wc); | 886 | struct ib_wc *wc); |
887 | int (*peek_cq)(struct ib_cq *cq, int wc_cnt); | 887 | int (*peek_cq)(struct ib_cq *cq, int wc_cnt); |
diff --git a/kernel/sched.c b/kernel/sched.c index ac3f5cc3bb51..b6506671b2be 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -815,7 +815,8 @@ static void activate_task(task_t *p, runqueue_t *rq, int local) | |||
815 | } | 815 | } |
816 | #endif | 816 | #endif |
817 | 817 | ||
818 | p->prio = recalc_task_prio(p, now); | 818 | if (!rt_task(p)) |
819 | p->prio = recalc_task_prio(p, now); | ||
819 | 820 | ||
820 | /* | 821 | /* |
821 | * This checks to make sure it's not an uninterruptible task | 822 | * This checks to make sure it's not an uninterruptible task |
diff --git a/kernel/signal.c b/kernel/signal.c index 1bf3c39d6109..80789a59b4db 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -1499,7 +1499,7 @@ void do_notify_parent(struct task_struct *tsk, int sig) | |||
1499 | 1499 | ||
1500 | psig = tsk->parent->sighand; | 1500 | psig = tsk->parent->sighand; |
1501 | spin_lock_irqsave(&psig->siglock, flags); | 1501 | spin_lock_irqsave(&psig->siglock, flags); |
1502 | if (sig == SIGCHLD && | 1502 | if (!tsk->ptrace && sig == SIGCHLD && |
1503 | (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN || | 1503 | (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN || |
1504 | (psig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT))) { | 1504 | (psig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT))) { |
1505 | /* | 1505 | /* |
diff --git a/kernel/sys.c b/kernel/sys.c index c43b3e22bbda..bce933ebb29f 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -1497,6 +1497,8 @@ EXPORT_SYMBOL(in_egroup_p); | |||
1497 | 1497 | ||
1498 | DECLARE_RWSEM(uts_sem); | 1498 | DECLARE_RWSEM(uts_sem); |
1499 | 1499 | ||
1500 | EXPORT_SYMBOL(uts_sem); | ||
1501 | |||
1500 | asmlinkage long sys_newuname(struct new_utsname __user * name) | 1502 | asmlinkage long sys_newuname(struct new_utsname __user * name) |
1501 | { | 1503 | { |
1502 | int errno = 0; | 1504 | int errno = 0; |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index ff81b5c65511..987225bdd661 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -1330,7 +1330,7 @@ void show_free_areas(void) | |||
1330 | } else | 1330 | } else |
1331 | printk("\n"); | 1331 | printk("\n"); |
1332 | 1332 | ||
1333 | for_each_cpu(cpu) { | 1333 | for_each_online_cpu(cpu) { |
1334 | struct per_cpu_pageset *pageset; | 1334 | struct per_cpu_pageset *pageset; |
1335 | 1335 | ||
1336 | pageset = zone_pcp(zone, cpu); | 1336 | pageset = zone_pcp(zone, cpu); |
diff --git a/net/core/datagram.c b/net/core/datagram.c index d219435d086c..1bcfef51ac58 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c | |||
@@ -350,6 +350,20 @@ fault: | |||
350 | return -EFAULT; | 350 | return -EFAULT; |
351 | } | 351 | } |
352 | 352 | ||
353 | unsigned int __skb_checksum_complete(struct sk_buff *skb) | ||
354 | { | ||
355 | unsigned int sum; | ||
356 | |||
357 | sum = (u16)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)); | ||
358 | if (likely(!sum)) { | ||
359 | if (unlikely(skb->ip_summed == CHECKSUM_HW)) | ||
360 | netdev_rx_csum_fault(skb->dev); | ||
361 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
362 | } | ||
363 | return sum; | ||
364 | } | ||
365 | EXPORT_SYMBOL(__skb_checksum_complete); | ||
366 | |||
353 | /** | 367 | /** |
354 | * skb_copy_and_csum_datagram_iovec - Copy and checkum skb to user iovec. | 368 | * skb_copy_and_csum_datagram_iovec - Copy and checkum skb to user iovec. |
355 | * @skb: skbuff | 369 | * @skb: skbuff |
@@ -363,7 +377,7 @@ fault: | |||
363 | * -EFAULT - fault during copy. Beware, in this case iovec | 377 | * -EFAULT - fault during copy. Beware, in this case iovec |
364 | * can be modified! | 378 | * can be modified! |
365 | */ | 379 | */ |
366 | int skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb, | 380 | int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb, |
367 | int hlen, struct iovec *iov) | 381 | int hlen, struct iovec *iov) |
368 | { | 382 | { |
369 | unsigned int csum; | 383 | unsigned int csum; |
@@ -376,8 +390,7 @@ int skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb, | |||
376 | iov++; | 390 | iov++; |
377 | 391 | ||
378 | if (iov->iov_len < chunk) { | 392 | if (iov->iov_len < chunk) { |
379 | if ((unsigned short)csum_fold(skb_checksum(skb, 0, chunk + hlen, | 393 | if (__skb_checksum_complete(skb)) |
380 | skb->csum))) | ||
381 | goto csum_error; | 394 | goto csum_error; |
382 | if (skb_copy_datagram_iovec(skb, hlen, iov, chunk)) | 395 | if (skb_copy_datagram_iovec(skb, hlen, iov, chunk)) |
383 | goto fault; | 396 | goto fault; |
@@ -388,6 +401,8 @@ int skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb, | |||
388 | goto fault; | 401 | goto fault; |
389 | if ((unsigned short)csum_fold(csum)) | 402 | if ((unsigned short)csum_fold(csum)) |
390 | goto csum_error; | 403 | goto csum_error; |
404 | if (unlikely(skb->ip_summed == CHECKSUM_HW)) | ||
405 | netdev_rx_csum_fault(skb->dev); | ||
391 | iov->iov_len -= chunk; | 406 | iov->iov_len -= chunk; |
392 | iov->iov_base += chunk; | 407 | iov->iov_base += chunk; |
393 | } | 408 | } |
diff --git a/net/core/dev.c b/net/core/dev.c index 8d1541595277..0b48e294aafe 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -1108,6 +1108,18 @@ out: | |||
1108 | return ret; | 1108 | return ret; |
1109 | } | 1109 | } |
1110 | 1110 | ||
1111 | /* Take action when hardware reception checksum errors are detected. */ | ||
1112 | #ifdef CONFIG_BUG | ||
1113 | void netdev_rx_csum_fault(struct net_device *dev) | ||
1114 | { | ||
1115 | if (net_ratelimit()) { | ||
1116 | printk(KERN_ERR "%s: hw csum failure.\n", dev->name); | ||
1117 | dump_stack(); | ||
1118 | } | ||
1119 | } | ||
1120 | EXPORT_SYMBOL(netdev_rx_csum_fault); | ||
1121 | #endif | ||
1122 | |||
1111 | #ifdef CONFIG_HIGHMEM | 1123 | #ifdef CONFIG_HIGHMEM |
1112 | /* Actually, we should eliminate this check as soon as we know, that: | 1124 | /* Actually, we should eliminate this check as soon as we know, that: |
1113 | * 1. IOMMU is present and allows to map all the memory. | 1125 | * 1. IOMMU is present and allows to map all the memory. |
diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 802fe11efad0..49424a42a2c0 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c | |||
@@ -101,16 +101,20 @@ void netpoll_queue(struct sk_buff *skb) | |||
101 | static int checksum_udp(struct sk_buff *skb, struct udphdr *uh, | 101 | static int checksum_udp(struct sk_buff *skb, struct udphdr *uh, |
102 | unsigned short ulen, u32 saddr, u32 daddr) | 102 | unsigned short ulen, u32 saddr, u32 daddr) |
103 | { | 103 | { |
104 | if (uh->check == 0) | 104 | unsigned int psum; |
105 | |||
106 | if (uh->check == 0 || skb->ip_summed == CHECKSUM_UNNECESSARY) | ||
105 | return 0; | 107 | return 0; |
106 | 108 | ||
107 | if (skb->ip_summed == CHECKSUM_HW) | 109 | psum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); |
108 | return csum_tcpudp_magic( | 110 | |
109 | saddr, daddr, ulen, IPPROTO_UDP, skb->csum); | 111 | if (skb->ip_summed == CHECKSUM_HW && |
112 | !(u16)csum_fold(csum_add(psum, skb->csum))) | ||
113 | return 0; | ||
110 | 114 | ||
111 | skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); | 115 | skb->csum = psum; |
112 | 116 | ||
113 | return csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)); | 117 | return __skb_checksum_complete(skb); |
114 | } | 118 | } |
115 | 119 | ||
116 | /* | 120 | /* |
@@ -489,7 +493,7 @@ int __netpoll_rx(struct sk_buff *skb) | |||
489 | 493 | ||
490 | if (ulen != len) | 494 | if (ulen != len) |
491 | goto out; | 495 | goto out; |
492 | if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr) < 0) | 496 | if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr)) |
493 | goto out; | 497 | goto out; |
494 | if (np->local_ip && np->local_ip != ntohl(iph->daddr)) | 498 | if (np->local_ip && np->local_ip != ntohl(iph->daddr)) |
495 | goto out; | 499 | goto out; |
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 9bed7569ce3f..8700379685e0 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #include <net/udp.h> | 49 | #include <net/udp.h> |
50 | #include <net/sock.h> | 50 | #include <net/sock.h> |
51 | #include <net/pkt_sched.h> | 51 | #include <net/pkt_sched.h> |
52 | #include <net/netlink.h> | ||
52 | 53 | ||
53 | DECLARE_MUTEX(rtnl_sem); | 54 | DECLARE_MUTEX(rtnl_sem); |
54 | 55 | ||
@@ -462,11 +463,6 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change) | |||
462 | netlink_broadcast(rtnl, skb, 0, RTNLGRP_LINK, GFP_KERNEL); | 463 | netlink_broadcast(rtnl, skb, 0, RTNLGRP_LINK, GFP_KERNEL); |
463 | } | 464 | } |
464 | 465 | ||
465 | static int rtnetlink_done(struct netlink_callback *cb) | ||
466 | { | ||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | /* Protected by RTNL sempahore. */ | 466 | /* Protected by RTNL sempahore. */ |
471 | static struct rtattr **rta_buf; | 467 | static struct rtattr **rta_buf; |
472 | static int rtattr_max; | 468 | static int rtattr_max; |
@@ -524,8 +520,6 @@ rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) | |||
524 | } | 520 | } |
525 | 521 | ||
526 | if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { | 522 | if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { |
527 | u32 rlen; | ||
528 | |||
529 | if (link->dumpit == NULL) | 523 | if (link->dumpit == NULL) |
530 | link = &(rtnetlink_links[PF_UNSPEC][type]); | 524 | link = &(rtnetlink_links[PF_UNSPEC][type]); |
531 | 525 | ||
@@ -533,14 +527,11 @@ rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) | |||
533 | goto err_inval; | 527 | goto err_inval; |
534 | 528 | ||
535 | if ((*errp = netlink_dump_start(rtnl, skb, nlh, | 529 | if ((*errp = netlink_dump_start(rtnl, skb, nlh, |
536 | link->dumpit, | 530 | link->dumpit, NULL)) != 0) { |
537 | rtnetlink_done)) != 0) { | ||
538 | return -1; | 531 | return -1; |
539 | } | 532 | } |
540 | rlen = NLMSG_ALIGN(nlh->nlmsg_len); | 533 | |
541 | if (rlen > skb->len) | 534 | netlink_queue_skip(nlh, skb); |
542 | rlen = skb->len; | ||
543 | skb_pull(skb, rlen); | ||
544 | return -1; | 535 | return -1; |
545 | } | 536 | } |
546 | 537 | ||
@@ -579,75 +570,13 @@ err_inval: | |||
579 | return -1; | 570 | return -1; |
580 | } | 571 | } |
581 | 572 | ||
582 | /* | ||
583 | * Process one packet of messages. | ||
584 | * Malformed skbs with wrong lengths of messages are discarded silently. | ||
585 | */ | ||
586 | |||
587 | static inline int rtnetlink_rcv_skb(struct sk_buff *skb) | ||
588 | { | ||
589 | int err; | ||
590 | struct nlmsghdr * nlh; | ||
591 | |||
592 | while (skb->len >= NLMSG_SPACE(0)) { | ||
593 | u32 rlen; | ||
594 | |||
595 | nlh = (struct nlmsghdr *)skb->data; | ||
596 | if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) | ||
597 | return 0; | ||
598 | rlen = NLMSG_ALIGN(nlh->nlmsg_len); | ||
599 | if (rlen > skb->len) | ||
600 | rlen = skb->len; | ||
601 | if (rtnetlink_rcv_msg(skb, nlh, &err)) { | ||
602 | /* Not error, but we must interrupt processing here: | ||
603 | * Note, that in this case we do not pull message | ||
604 | * from skb, it will be processed later. | ||
605 | */ | ||
606 | if (err == 0) | ||
607 | return -1; | ||
608 | netlink_ack(skb, nlh, err); | ||
609 | } else if (nlh->nlmsg_flags&NLM_F_ACK) | ||
610 | netlink_ack(skb, nlh, 0); | ||
611 | skb_pull(skb, rlen); | ||
612 | } | ||
613 | |||
614 | return 0; | ||
615 | } | ||
616 | |||
617 | /* | ||
618 | * rtnetlink input queue processing routine: | ||
619 | * - process as much as there was in the queue upon entry. | ||
620 | * - feed skbs to rtnetlink_rcv_skb, until it refuse a message, | ||
621 | * that will occur, when a dump started. | ||
622 | */ | ||
623 | |||
624 | static void rtnetlink_rcv(struct sock *sk, int len) | 573 | static void rtnetlink_rcv(struct sock *sk, int len) |
625 | { | 574 | { |
626 | unsigned int qlen = skb_queue_len(&sk->sk_receive_queue); | 575 | unsigned int qlen = 0; |
627 | 576 | ||
628 | do { | 577 | do { |
629 | struct sk_buff *skb; | ||
630 | |||
631 | rtnl_lock(); | 578 | rtnl_lock(); |
632 | 579 | netlink_run_queue(sk, &qlen, &rtnetlink_rcv_msg); | |
633 | if (qlen > skb_queue_len(&sk->sk_receive_queue)) | ||
634 | qlen = skb_queue_len(&sk->sk_receive_queue); | ||
635 | |||
636 | for (; qlen; qlen--) { | ||
637 | skb = skb_dequeue(&sk->sk_receive_queue); | ||
638 | if (rtnetlink_rcv_skb(skb)) { | ||
639 | if (skb->len) | ||
640 | skb_queue_head(&sk->sk_receive_queue, | ||
641 | skb); | ||
642 | else { | ||
643 | kfree_skb(skb); | ||
644 | qlen--; | ||
645 | } | ||
646 | break; | ||
647 | } | ||
648 | kfree_skb(skb); | ||
649 | } | ||
650 | |||
651 | up(&rtnl_sem); | 580 | up(&rtnl_sem); |
652 | 581 | ||
653 | netdev_run_todo(); | 582 | netdev_run_todo(); |
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 95501e40100e..b7d13a4fff48 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -336,6 +336,9 @@ void __kfree_skb(struct sk_buff *skb) | |||
336 | } | 336 | } |
337 | #ifdef CONFIG_NETFILTER | 337 | #ifdef CONFIG_NETFILTER |
338 | nf_conntrack_put(skb->nfct); | 338 | nf_conntrack_put(skb->nfct); |
339 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | ||
340 | nf_conntrack_put_reasm(skb->nfct_reasm); | ||
341 | #endif | ||
339 | #ifdef CONFIG_BRIDGE_NETFILTER | 342 | #ifdef CONFIG_BRIDGE_NETFILTER |
340 | nf_bridge_put(skb->nf_bridge); | 343 | nf_bridge_put(skb->nf_bridge); |
341 | #endif | 344 | #endif |
@@ -414,9 +417,17 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask) | |||
414 | C(nfct); | 417 | C(nfct); |
415 | nf_conntrack_get(skb->nfct); | 418 | nf_conntrack_get(skb->nfct); |
416 | C(nfctinfo); | 419 | C(nfctinfo); |
420 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | ||
421 | C(nfct_reasm); | ||
422 | nf_conntrack_get_reasm(skb->nfct_reasm); | ||
423 | #endif | ||
417 | #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE) | 424 | #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE) |
418 | C(ipvs_property); | 425 | C(ipvs_property); |
419 | #endif | 426 | #endif |
427 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | ||
428 | C(nfct_reasm); | ||
429 | nf_conntrack_get_reasm(skb->nfct_reasm); | ||
430 | #endif | ||
420 | #ifdef CONFIG_BRIDGE_NETFILTER | 431 | #ifdef CONFIG_BRIDGE_NETFILTER |
421 | C(nf_bridge); | 432 | C(nf_bridge); |
422 | nf_bridge_get(skb->nf_bridge); | 433 | nf_bridge_get(skb->nf_bridge); |
@@ -474,6 +485,10 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) | |||
474 | new->nfct = old->nfct; | 485 | new->nfct = old->nfct; |
475 | nf_conntrack_get(old->nfct); | 486 | nf_conntrack_get(old->nfct); |
476 | new->nfctinfo = old->nfctinfo; | 487 | new->nfctinfo = old->nfctinfo; |
488 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | ||
489 | new->nfct_reasm = old->nfct_reasm; | ||
490 | nf_conntrack_get_reasm(old->nfct_reasm); | ||
491 | #endif | ||
477 | #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE) | 492 | #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE) |
478 | new->ipvs_property = old->ipvs_property; | 493 | new->ipvs_property = old->ipvs_property; |
479 | #endif | 494 | #endif |
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 175e093ec564..e3eceecd0496 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c | |||
@@ -934,11 +934,11 @@ int icmp_rcv(struct sk_buff *skb) | |||
934 | case CHECKSUM_HW: | 934 | case CHECKSUM_HW: |
935 | if (!(u16)csum_fold(skb->csum)) | 935 | if (!(u16)csum_fold(skb->csum)) |
936 | break; | 936 | break; |
937 | LIMIT_NETDEBUG(KERN_DEBUG "icmp v4 hw csum failure\n"); | 937 | /* fall through */ |
938 | case CHECKSUM_NONE: | 938 | case CHECKSUM_NONE: |
939 | if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0))) | 939 | skb->csum = 0; |
940 | if (__skb_checksum_complete(skb)) | ||
940 | goto error; | 941 | goto error; |
941 | default:; | ||
942 | } | 942 | } |
943 | 943 | ||
944 | if (!pskb_pull(skb, sizeof(struct icmphdr))) | 944 | if (!pskb_pull(skb, sizeof(struct icmphdr))) |
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index c6247fc84060..c04607b49212 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c | |||
@@ -872,11 +872,18 @@ int igmp_rcv(struct sk_buff *skb) | |||
872 | return 0; | 872 | return 0; |
873 | } | 873 | } |
874 | 874 | ||
875 | if (!pskb_may_pull(skb, sizeof(struct igmphdr)) || | 875 | if (!pskb_may_pull(skb, sizeof(struct igmphdr))) |
876 | (u16)csum_fold(skb_checksum(skb, 0, len, 0))) { | 876 | goto drop; |
877 | in_dev_put(in_dev); | 877 | |
878 | kfree_skb(skb); | 878 | switch (skb->ip_summed) { |
879 | return 0; | 879 | case CHECKSUM_HW: |
880 | if (!(u16)csum_fold(skb->csum)) | ||
881 | break; | ||
882 | /* fall through */ | ||
883 | case CHECKSUM_NONE: | ||
884 | skb->csum = 0; | ||
885 | if (__skb_checksum_complete(skb)) | ||
886 | goto drop; | ||
880 | } | 887 | } |
881 | 888 | ||
882 | ih = skb->h.igmph; | 889 | ih = skb->h.igmph; |
@@ -906,6 +913,8 @@ int igmp_rcv(struct sk_buff *skb) | |||
906 | default: | 913 | default: |
907 | NETDEBUG(KERN_DEBUG "New IGMP type=%d, why we do not know about it?\n", ih->type); | 914 | NETDEBUG(KERN_DEBUG "New IGMP type=%d, why we do not know about it?\n", ih->type); |
908 | } | 915 | } |
916 | |||
917 | drop: | ||
909 | in_dev_put(in_dev); | 918 | in_dev_put(in_dev); |
910 | kfree_skb(skb); | 919 | kfree_skb(skb); |
911 | return 0; | 920 | return 0; |
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 71f3c7350c6e..39061ed53cfd 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c | |||
@@ -724,12 +724,6 @@ done: | |||
724 | return skb->len; | 724 | return skb->len; |
725 | } | 725 | } |
726 | 726 | ||
727 | static int inet_diag_dump_done(struct netlink_callback *cb) | ||
728 | { | ||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | |||
733 | static __inline__ int | 727 | static __inline__ int |
734 | inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | 728 | inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) |
735 | { | 729 | { |
@@ -760,8 +754,7 @@ inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
760 | goto err_inval; | 754 | goto err_inval; |
761 | } | 755 | } |
762 | return netlink_dump_start(idiagnl, skb, nlh, | 756 | return netlink_dump_start(idiagnl, skb, nlh, |
763 | inet_diag_dump, | 757 | inet_diag_dump, NULL); |
764 | inet_diag_dump_done); | ||
765 | } else { | 758 | } else { |
766 | return inet_diag_get_exact(skb, nlh); | 759 | return inet_diag_get_exact(skb, nlh); |
767 | } | 760 | } |
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 896ce3f8f53a..4e9c74b54b15 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c | |||
@@ -577,15 +577,16 @@ static int ipgre_rcv(struct sk_buff *skb) | |||
577 | goto drop_nolock; | 577 | goto drop_nolock; |
578 | 578 | ||
579 | if (flags&GRE_CSUM) { | 579 | if (flags&GRE_CSUM) { |
580 | if (skb->ip_summed == CHECKSUM_HW) { | 580 | switch (skb->ip_summed) { |
581 | case CHECKSUM_HW: | ||
581 | csum = (u16)csum_fold(skb->csum); | 582 | csum = (u16)csum_fold(skb->csum); |
582 | if (csum) | 583 | if (!csum) |
583 | skb->ip_summed = CHECKSUM_NONE; | 584 | break; |
584 | } | 585 | /* fall through */ |
585 | if (skb->ip_summed == CHECKSUM_NONE) { | 586 | case CHECKSUM_NONE: |
586 | skb->csum = skb_checksum(skb, 0, skb->len, 0); | 587 | skb->csum = 0; |
588 | csum = __skb_checksum_complete(skb); | ||
587 | skb->ip_summed = CHECKSUM_HW; | 589 | skb->ip_summed = CHECKSUM_HW; |
588 | csum = (u16)csum_fold(skb->csum); | ||
589 | } | 590 | } |
590 | offset += 4; | 591 | offset += 4; |
591 | } | 592 | } |
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 7d917e4ce1d9..9d3c8b5f327e 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig | |||
@@ -5,6 +5,20 @@ | |||
5 | menu "IP: Netfilter Configuration" | 5 | menu "IP: Netfilter Configuration" |
6 | depends on INET && NETFILTER | 6 | depends on INET && NETFILTER |
7 | 7 | ||
8 | config NF_CONNTRACK_IPV4 | ||
9 | tristate "IPv4 support for new connection tracking (EXPERIMENTAL)" | ||
10 | depends on EXPERIMENTAL && NF_CONNTRACK | ||
11 | ---help--- | ||
12 | Connection tracking keeps a record of what packets have passed | ||
13 | through your machine, in order to figure out how they are related | ||
14 | into connections. | ||
15 | |||
16 | This is IPv4 support on Layer 3 independent connection tracking. | ||
17 | Layer 3 independent connection tracking is experimental scheme | ||
18 | which generalize ip_conntrack to support other layer 3 protocols. | ||
19 | |||
20 | To compile it as a module, choose M here. If unsure, say N. | ||
21 | |||
8 | # connection tracking, helpers and protocols | 22 | # connection tracking, helpers and protocols |
9 | config IP_NF_CONNTRACK | 23 | config IP_NF_CONNTRACK |
10 | tristate "Connection tracking (required for masq/NAT)" | 24 | tristate "Connection tracking (required for masq/NAT)" |
@@ -209,8 +223,8 @@ config IP_NF_MATCH_PKTTYPE | |||
209 | tristate "Packet type match support" | 223 | tristate "Packet type match support" |
210 | depends on IP_NF_IPTABLES | 224 | depends on IP_NF_IPTABLES |
211 | help | 225 | help |
212 | Packet type matching allows you to match a packet by | 226 | Packet type matching allows you to match a packet by |
213 | its "class", eg. BROADCAST, MULTICAST, ... | 227 | its "class", eg. BROADCAST, MULTICAST, ... |
214 | 228 | ||
215 | Typical usage: | 229 | Typical usage: |
216 | iptables -A INPUT -m pkttype --pkt-type broadcast -j LOG | 230 | iptables -A INPUT -m pkttype --pkt-type broadcast -j LOG |
@@ -317,7 +331,8 @@ config IP_NF_MATCH_TCPMSS | |||
317 | 331 | ||
318 | config IP_NF_MATCH_HELPER | 332 | config IP_NF_MATCH_HELPER |
319 | tristate "Helper match support" | 333 | tristate "Helper match support" |
320 | depends on IP_NF_CONNTRACK && IP_NF_IPTABLES | 334 | depends on IP_NF_IPTABLES |
335 | depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4 | ||
321 | help | 336 | help |
322 | Helper matching allows you to match packets in dynamic connections | 337 | Helper matching allows you to match packets in dynamic connections |
323 | tracked by a conntrack-helper, ie. ip_conntrack_ftp | 338 | tracked by a conntrack-helper, ie. ip_conntrack_ftp |
@@ -326,7 +341,8 @@ config IP_NF_MATCH_HELPER | |||
326 | 341 | ||
327 | config IP_NF_MATCH_STATE | 342 | config IP_NF_MATCH_STATE |
328 | tristate "Connection state match support" | 343 | tristate "Connection state match support" |
329 | depends on IP_NF_CONNTRACK && IP_NF_IPTABLES | 344 | depends on IP_NF_IPTABLES |
345 | depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4 | ||
330 | help | 346 | help |
331 | Connection state matching allows you to match packets based on their | 347 | Connection state matching allows you to match packets based on their |
332 | relationship to a tracked connection (ie. previous packets). This | 348 | relationship to a tracked connection (ie. previous packets). This |
@@ -336,7 +352,8 @@ config IP_NF_MATCH_STATE | |||
336 | 352 | ||
337 | config IP_NF_MATCH_CONNTRACK | 353 | config IP_NF_MATCH_CONNTRACK |
338 | tristate "Connection tracking match support" | 354 | tristate "Connection tracking match support" |
339 | depends on IP_NF_CONNTRACK && IP_NF_IPTABLES | 355 | depends on IP_NF_IPTABLES |
356 | depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4 | ||
340 | help | 357 | help |
341 | This is a general conntrack match module, a superset of the state match. | 358 | This is a general conntrack match module, a superset of the state match. |
342 | 359 | ||
@@ -422,7 +439,8 @@ config IP_NF_MATCH_COMMENT | |||
422 | 439 | ||
423 | config IP_NF_MATCH_CONNMARK | 440 | config IP_NF_MATCH_CONNMARK |
424 | tristate 'Connection mark match support' | 441 | tristate 'Connection mark match support' |
425 | depends on IP_NF_CONNTRACK_MARK && IP_NF_IPTABLES | 442 | depends on IP_NF_IPTABLES |
443 | depends on IP_NF_CONNTRACK_MARK || (NF_CONNTRACK_MARK && NF_CONNTRACK_IPV4) | ||
426 | help | 444 | help |
427 | This option adds a `connmark' match, which allows you to match the | 445 | This option adds a `connmark' match, which allows you to match the |
428 | connection mark value previously set for the session by `CONNMARK'. | 446 | connection mark value previously set for the session by `CONNMARK'. |
@@ -433,7 +451,8 @@ config IP_NF_MATCH_CONNMARK | |||
433 | 451 | ||
434 | config IP_NF_MATCH_CONNBYTES | 452 | config IP_NF_MATCH_CONNBYTES |
435 | tristate 'Connection byte/packet counter match support' | 453 | tristate 'Connection byte/packet counter match support' |
436 | depends on IP_NF_CT_ACCT && IP_NF_IPTABLES | 454 | depends on IP_NF_IPTABLES |
455 | depends on IP_NF_CT_ACCT || (NF_CT_ACCT && NF_CONNTRACK_IPV4) | ||
437 | help | 456 | help |
438 | This option adds a `connbytes' match, which allows you to match the | 457 | This option adds a `connbytes' match, which allows you to match the |
439 | number of bytes and/or packets for each direction within a connection. | 458 | number of bytes and/or packets for each direction within a connection. |
@@ -747,7 +766,8 @@ config IP_NF_TARGET_TTL | |||
747 | 766 | ||
748 | config IP_NF_TARGET_CONNMARK | 767 | config IP_NF_TARGET_CONNMARK |
749 | tristate 'CONNMARK target support' | 768 | tristate 'CONNMARK target support' |
750 | depends on IP_NF_CONNTRACK_MARK && IP_NF_MANGLE | 769 | depends on IP_NF_MANGLE |
770 | depends on IP_NF_CONNTRACK_MARK || (NF_CONNTRACK_MARK && NF_CONNTRACK_IPV4) | ||
751 | help | 771 | help |
752 | This option adds a `CONNMARK' target, which allows one to manipulate | 772 | This option adds a `CONNMARK' target, which allows one to manipulate |
753 | the connection mark value. Similar to the MARK target, but | 773 | the connection mark value. Similar to the MARK target, but |
@@ -759,7 +779,8 @@ config IP_NF_TARGET_CONNMARK | |||
759 | 779 | ||
760 | config IP_NF_TARGET_CLUSTERIP | 780 | config IP_NF_TARGET_CLUSTERIP |
761 | tristate "CLUSTERIP target support (EXPERIMENTAL)" | 781 | tristate "CLUSTERIP target support (EXPERIMENTAL)" |
762 | depends on IP_NF_CONNTRACK_MARK && IP_NF_IPTABLES && EXPERIMENTAL | 782 | depends on IP_NF_IPTABLES && EXPERIMENTAL |
783 | depends on IP_NF_CONNTRACK_MARK || (NF_CONNTRACK_MARK && NF_CONNTRACK_IPV4) | ||
763 | help | 784 | help |
764 | The CLUSTERIP target allows you to build load-balancing clusters of | 785 | The CLUSTERIP target allows you to build load-balancing clusters of |
765 | network servers without having a dedicated load-balancing | 786 | network servers without having a dedicated load-balancing |
@@ -782,7 +803,7 @@ config IP_NF_RAW | |||
782 | config IP_NF_TARGET_NOTRACK | 803 | config IP_NF_TARGET_NOTRACK |
783 | tristate 'NOTRACK target support' | 804 | tristate 'NOTRACK target support' |
784 | depends on IP_NF_RAW | 805 | depends on IP_NF_RAW |
785 | depends on IP_NF_CONNTRACK | 806 | depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4 |
786 | help | 807 | help |
787 | The NOTRACK target allows a select rule to specify | 808 | The NOTRACK target allows a select rule to specify |
788 | which packets *not* to enter the conntrack/NAT | 809 | which packets *not* to enter the conntrack/NAT |
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index dab4b58dd31e..058c48e258fc 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile | |||
@@ -103,3 +103,9 @@ obj-$(CONFIG_IP_NF_ARP_MANGLE) += arpt_mangle.o | |||
103 | obj-$(CONFIG_IP_NF_ARPFILTER) += arptable_filter.o | 103 | obj-$(CONFIG_IP_NF_ARPFILTER) += arptable_filter.o |
104 | 104 | ||
105 | obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o | 105 | obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o |
106 | |||
107 | # objects for l3 independent conntrack | ||
108 | nf_conntrack_ipv4-objs := nf_conntrack_l3proto_ipv4.o nf_conntrack_proto_icmp.o | ||
109 | |||
110 | # l3 independent conntrack | ||
111 | obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index 5c1c0a3d1c4b..d2a4fec22862 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c | |||
@@ -1376,7 +1376,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, | |||
1376 | ip_conntrack_expect_put(exp); | 1376 | ip_conntrack_expect_put(exp); |
1377 | } | 1377 | } |
1378 | } | 1378 | } |
1379 | write_unlock(&ip_conntrack_lock); | 1379 | write_unlock_bh(&ip_conntrack_lock); |
1380 | } else { | 1380 | } else { |
1381 | /* This basically means we have to flush everything*/ | 1381 | /* This basically means we have to flush everything*/ |
1382 | write_lock_bh(&ip_conntrack_lock); | 1382 | write_lock_bh(&ip_conntrack_lock); |
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c index 5198f3a1e2cd..e4d6b268e8c4 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/in.h> | 13 | #include <linux/in.h> |
14 | #include <linux/icmp.h> | 14 | #include <linux/icmp.h> |
15 | #include <linux/seq_file.h> | 15 | #include <linux/seq_file.h> |
16 | #include <linux/skbuff.h> | ||
16 | #include <net/ip.h> | 17 | #include <net/ip.h> |
17 | #include <net/checksum.h> | 18 | #include <net/checksum.h> |
18 | #include <linux/netfilter.h> | 19 | #include <linux/netfilter.h> |
@@ -230,19 +231,15 @@ icmp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo, | |||
230 | case CHECKSUM_HW: | 231 | case CHECKSUM_HW: |
231 | if (!(u16)csum_fold(skb->csum)) | 232 | if (!(u16)csum_fold(skb->csum)) |
232 | break; | 233 | break; |
233 | if (LOG_INVALID(IPPROTO_ICMP)) | 234 | /* fall through */ |
234 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, | ||
235 | "ip_ct_icmp: bad HW ICMP checksum "); | ||
236 | return -NF_ACCEPT; | ||
237 | case CHECKSUM_NONE: | 235 | case CHECKSUM_NONE: |
238 | if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0))) { | 236 | skb->csum = 0; |
237 | if (__skb_checksum_complete(skb)) { | ||
239 | if (LOG_INVALID(IPPROTO_ICMP)) | 238 | if (LOG_INVALID(IPPROTO_ICMP)) |
240 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, | 239 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, |
241 | "ip_ct_icmp: bad ICMP checksum "); | 240 | "ip_ct_icmp: bad ICMP checksum "); |
242 | return -NF_ACCEPT; | 241 | return -NF_ACCEPT; |
243 | } | 242 | } |
244 | default: | ||
245 | break; | ||
246 | } | 243 | } |
247 | 244 | ||
248 | checksum_skipped: | 245 | checksum_skipped: |
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 9bcb398fbc1f..45c52d8f4d99 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c | |||
@@ -29,7 +29,7 @@ | |||
29 | 29 | ||
30 | #include <linux/netfilter_ipv4/ip_tables.h> | 30 | #include <linux/netfilter_ipv4/ip_tables.h> |
31 | #include <linux/netfilter_ipv4/ipt_CLUSTERIP.h> | 31 | #include <linux/netfilter_ipv4/ipt_CLUSTERIP.h> |
32 | #include <linux/netfilter_ipv4/ip_conntrack.h> | 32 | #include <net/netfilter/nf_conntrack_compat.h> |
33 | 33 | ||
34 | #define CLUSTERIP_VERSION "0.8" | 34 | #define CLUSTERIP_VERSION "0.8" |
35 | 35 | ||
@@ -316,14 +316,14 @@ target(struct sk_buff **pskb, | |||
316 | { | 316 | { |
317 | const struct ipt_clusterip_tgt_info *cipinfo = targinfo; | 317 | const struct ipt_clusterip_tgt_info *cipinfo = targinfo; |
318 | enum ip_conntrack_info ctinfo; | 318 | enum ip_conntrack_info ctinfo; |
319 | struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo); | 319 | u_int32_t *mark, hash; |
320 | u_int32_t hash; | ||
321 | 320 | ||
322 | /* don't need to clusterip_config_get() here, since refcount | 321 | /* don't need to clusterip_config_get() here, since refcount |
323 | * is only decremented by destroy() - and ip_tables guarantees | 322 | * is only decremented by destroy() - and ip_tables guarantees |
324 | * that the ->target() function isn't called after ->destroy() */ | 323 | * that the ->target() function isn't called after ->destroy() */ |
325 | 324 | ||
326 | if (!ct) { | 325 | mark = nf_ct_get_mark((*pskb), &ctinfo); |
326 | if (mark == NULL) { | ||
327 | printk(KERN_ERR "CLUSTERIP: no conntrack!\n"); | 327 | printk(KERN_ERR "CLUSTERIP: no conntrack!\n"); |
328 | /* FIXME: need to drop invalid ones, since replies | 328 | /* FIXME: need to drop invalid ones, since replies |
329 | * to outgoing connections of other nodes will be | 329 | * to outgoing connections of other nodes will be |
@@ -346,7 +346,7 @@ target(struct sk_buff **pskb, | |||
346 | 346 | ||
347 | switch (ctinfo) { | 347 | switch (ctinfo) { |
348 | case IP_CT_NEW: | 348 | case IP_CT_NEW: |
349 | ct->mark = hash; | 349 | *mark = hash; |
350 | break; | 350 | break; |
351 | case IP_CT_RELATED: | 351 | case IP_CT_RELATED: |
352 | case IP_CT_RELATED+IP_CT_IS_REPLY: | 352 | case IP_CT_RELATED+IP_CT_IS_REPLY: |
@@ -363,7 +363,7 @@ target(struct sk_buff **pskb, | |||
363 | #ifdef DEBUG_CLUSTERP | 363 | #ifdef DEBUG_CLUSTERP |
364 | DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | 364 | DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); |
365 | #endif | 365 | #endif |
366 | DEBUGP("hash=%u ct_hash=%u ", hash, ct->mark); | 366 | DEBUGP("hash=%u ct_hash=%u ", hash, *mark); |
367 | if (!clusterip_responsible(cipinfo->config, hash)) { | 367 | if (!clusterip_responsible(cipinfo->config, hash)) { |
368 | DEBUGP("not responsible\n"); | 368 | DEBUGP("not responsible\n"); |
369 | return NF_DROP; | 369 | return NF_DROP; |
diff --git a/net/ipv4/netfilter/ipt_CONNMARK.c b/net/ipv4/netfilter/ipt_CONNMARK.c index 05d66ab59424..8acac5a40a92 100644 --- a/net/ipv4/netfilter/ipt_CONNMARK.c +++ b/net/ipv4/netfilter/ipt_CONNMARK.c | |||
@@ -29,7 +29,7 @@ MODULE_LICENSE("GPL"); | |||
29 | 29 | ||
30 | #include <linux/netfilter_ipv4/ip_tables.h> | 30 | #include <linux/netfilter_ipv4/ip_tables.h> |
31 | #include <linux/netfilter_ipv4/ipt_CONNMARK.h> | 31 | #include <linux/netfilter_ipv4/ipt_CONNMARK.h> |
32 | #include <linux/netfilter_ipv4/ip_conntrack.h> | 32 | #include <net/netfilter/nf_conntrack_compat.h> |
33 | 33 | ||
34 | static unsigned int | 34 | static unsigned int |
35 | target(struct sk_buff **pskb, | 35 | target(struct sk_buff **pskb, |
@@ -43,24 +43,24 @@ target(struct sk_buff **pskb, | |||
43 | u_int32_t diff; | 43 | u_int32_t diff; |
44 | u_int32_t nfmark; | 44 | u_int32_t nfmark; |
45 | u_int32_t newmark; | 45 | u_int32_t newmark; |
46 | u_int32_t ctinfo; | ||
47 | u_int32_t *ctmark = nf_ct_get_mark(*pskb, &ctinfo); | ||
46 | 48 | ||
47 | enum ip_conntrack_info ctinfo; | 49 | if (ctmark) { |
48 | struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo); | ||
49 | if (ct) { | ||
50 | switch(markinfo->mode) { | 50 | switch(markinfo->mode) { |
51 | case IPT_CONNMARK_SET: | 51 | case IPT_CONNMARK_SET: |
52 | newmark = (ct->mark & ~markinfo->mask) | markinfo->mark; | 52 | newmark = (*ctmark & ~markinfo->mask) | markinfo->mark; |
53 | if (newmark != ct->mark) | 53 | if (newmark != *ctmark) |
54 | ct->mark = newmark; | 54 | *ctmark = newmark; |
55 | break; | 55 | break; |
56 | case IPT_CONNMARK_SAVE: | 56 | case IPT_CONNMARK_SAVE: |
57 | newmark = (ct->mark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask); | 57 | newmark = (*ctmark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask); |
58 | if (ct->mark != newmark) | 58 | if (*ctmark != newmark) |
59 | ct->mark = newmark; | 59 | *ctmark = newmark; |
60 | break; | 60 | break; |
61 | case IPT_CONNMARK_RESTORE: | 61 | case IPT_CONNMARK_RESTORE: |
62 | nfmark = (*pskb)->nfmark; | 62 | nfmark = (*pskb)->nfmark; |
63 | diff = (ct->mark ^ nfmark) & markinfo->mask; | 63 | diff = (*ctmark ^ nfmark) & markinfo->mask; |
64 | if (diff != 0) | 64 | if (diff != 0) |
65 | (*pskb)->nfmark = nfmark ^ diff; | 65 | (*pskb)->nfmark = nfmark ^ diff; |
66 | break; | 66 | break; |
diff --git a/net/ipv4/netfilter/ipt_NOTRACK.c b/net/ipv4/netfilter/ipt_NOTRACK.c index a4bb9b3bc292..e3c69d072c6e 100644 --- a/net/ipv4/netfilter/ipt_NOTRACK.c +++ b/net/ipv4/netfilter/ipt_NOTRACK.c | |||
@@ -5,7 +5,7 @@ | |||
5 | #include <linux/skbuff.h> | 5 | #include <linux/skbuff.h> |
6 | 6 | ||
7 | #include <linux/netfilter_ipv4/ip_tables.h> | 7 | #include <linux/netfilter_ipv4/ip_tables.h> |
8 | #include <linux/netfilter_ipv4/ip_conntrack.h> | 8 | #include <net/netfilter/nf_conntrack_compat.h> |
9 | 9 | ||
10 | static unsigned int | 10 | static unsigned int |
11 | target(struct sk_buff **pskb, | 11 | target(struct sk_buff **pskb, |
@@ -23,7 +23,7 @@ target(struct sk_buff **pskb, | |||
23 | If there is a real ct entry correspondig to this packet, | 23 | If there is a real ct entry correspondig to this packet, |
24 | it'll hang aroun till timing out. We don't deal with it | 24 | it'll hang aroun till timing out. We don't deal with it |
25 | for performance reasons. JK */ | 25 | for performance reasons. JK */ |
26 | (*pskb)->nfct = &ip_conntrack_untracked.ct_general; | 26 | nf_ct_untrack(*pskb); |
27 | (*pskb)->nfctinfo = IP_CT_NEW; | 27 | (*pskb)->nfctinfo = IP_CT_NEW; |
28 | nf_conntrack_get((*pskb)->nfct); | 28 | nf_conntrack_get((*pskb)->nfct); |
29 | 29 | ||
diff --git a/net/ipv4/netfilter/ipt_connbytes.c b/net/ipv4/netfilter/ipt_connbytes.c index df4a42c6da22..d68a048b7176 100644 --- a/net/ipv4/netfilter/ipt_connbytes.c +++ b/net/ipv4/netfilter/ipt_connbytes.c | |||
@@ -10,7 +10,7 @@ | |||
10 | */ | 10 | */ |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/skbuff.h> | 12 | #include <linux/skbuff.h> |
13 | #include <linux/netfilter_ipv4/ip_conntrack.h> | 13 | #include <net/netfilter/nf_conntrack_compat.h> |
14 | #include <linux/netfilter_ipv4/ip_tables.h> | 14 | #include <linux/netfilter_ipv4/ip_tables.h> |
15 | #include <linux/netfilter_ipv4/ipt_connbytes.h> | 15 | #include <linux/netfilter_ipv4/ipt_connbytes.h> |
16 | 16 | ||
@@ -46,60 +46,59 @@ match(const struct sk_buff *skb, | |||
46 | int *hotdrop) | 46 | int *hotdrop) |
47 | { | 47 | { |
48 | const struct ipt_connbytes_info *sinfo = matchinfo; | 48 | const struct ipt_connbytes_info *sinfo = matchinfo; |
49 | enum ip_conntrack_info ctinfo; | ||
50 | struct ip_conntrack *ct; | ||
51 | u_int64_t what = 0; /* initialize to make gcc happy */ | 49 | u_int64_t what = 0; /* initialize to make gcc happy */ |
50 | const struct ip_conntrack_counter *counters; | ||
52 | 51 | ||
53 | if (!(ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo))) | 52 | if (!(counters = nf_ct_get_counters(skb))) |
54 | return 0; /* no match */ | 53 | return 0; /* no match */ |
55 | 54 | ||
56 | switch (sinfo->what) { | 55 | switch (sinfo->what) { |
57 | case IPT_CONNBYTES_PKTS: | 56 | case IPT_CONNBYTES_PKTS: |
58 | switch (sinfo->direction) { | 57 | switch (sinfo->direction) { |
59 | case IPT_CONNBYTES_DIR_ORIGINAL: | 58 | case IPT_CONNBYTES_DIR_ORIGINAL: |
60 | what = ct->counters[IP_CT_DIR_ORIGINAL].packets; | 59 | what = counters[IP_CT_DIR_ORIGINAL].packets; |
61 | break; | 60 | break; |
62 | case IPT_CONNBYTES_DIR_REPLY: | 61 | case IPT_CONNBYTES_DIR_REPLY: |
63 | what = ct->counters[IP_CT_DIR_REPLY].packets; | 62 | what = counters[IP_CT_DIR_REPLY].packets; |
64 | break; | 63 | break; |
65 | case IPT_CONNBYTES_DIR_BOTH: | 64 | case IPT_CONNBYTES_DIR_BOTH: |
66 | what = ct->counters[IP_CT_DIR_ORIGINAL].packets; | 65 | what = counters[IP_CT_DIR_ORIGINAL].packets; |
67 | what += ct->counters[IP_CT_DIR_REPLY].packets; | 66 | what += counters[IP_CT_DIR_REPLY].packets; |
68 | break; | 67 | break; |
69 | } | 68 | } |
70 | break; | 69 | break; |
71 | case IPT_CONNBYTES_BYTES: | 70 | case IPT_CONNBYTES_BYTES: |
72 | switch (sinfo->direction) { | 71 | switch (sinfo->direction) { |
73 | case IPT_CONNBYTES_DIR_ORIGINAL: | 72 | case IPT_CONNBYTES_DIR_ORIGINAL: |
74 | what = ct->counters[IP_CT_DIR_ORIGINAL].bytes; | 73 | what = counters[IP_CT_DIR_ORIGINAL].bytes; |
75 | break; | 74 | break; |
76 | case IPT_CONNBYTES_DIR_REPLY: | 75 | case IPT_CONNBYTES_DIR_REPLY: |
77 | what = ct->counters[IP_CT_DIR_REPLY].bytes; | 76 | what = counters[IP_CT_DIR_REPLY].bytes; |
78 | break; | 77 | break; |
79 | case IPT_CONNBYTES_DIR_BOTH: | 78 | case IPT_CONNBYTES_DIR_BOTH: |
80 | what = ct->counters[IP_CT_DIR_ORIGINAL].bytes; | 79 | what = counters[IP_CT_DIR_ORIGINAL].bytes; |
81 | what += ct->counters[IP_CT_DIR_REPLY].bytes; | 80 | what += counters[IP_CT_DIR_REPLY].bytes; |
82 | break; | 81 | break; |
83 | } | 82 | } |
84 | break; | 83 | break; |
85 | case IPT_CONNBYTES_AVGPKT: | 84 | case IPT_CONNBYTES_AVGPKT: |
86 | switch (sinfo->direction) { | 85 | switch (sinfo->direction) { |
87 | case IPT_CONNBYTES_DIR_ORIGINAL: | 86 | case IPT_CONNBYTES_DIR_ORIGINAL: |
88 | what = div64_64(ct->counters[IP_CT_DIR_ORIGINAL].bytes, | 87 | what = div64_64(counters[IP_CT_DIR_ORIGINAL].bytes, |
89 | ct->counters[IP_CT_DIR_ORIGINAL].packets); | 88 | counters[IP_CT_DIR_ORIGINAL].packets); |
90 | break; | 89 | break; |
91 | case IPT_CONNBYTES_DIR_REPLY: | 90 | case IPT_CONNBYTES_DIR_REPLY: |
92 | what = div64_64(ct->counters[IP_CT_DIR_REPLY].bytes, | 91 | what = div64_64(counters[IP_CT_DIR_REPLY].bytes, |
93 | ct->counters[IP_CT_DIR_REPLY].packets); | 92 | counters[IP_CT_DIR_REPLY].packets); |
94 | break; | 93 | break; |
95 | case IPT_CONNBYTES_DIR_BOTH: | 94 | case IPT_CONNBYTES_DIR_BOTH: |
96 | { | 95 | { |
97 | u_int64_t bytes; | 96 | u_int64_t bytes; |
98 | u_int64_t pkts; | 97 | u_int64_t pkts; |
99 | bytes = ct->counters[IP_CT_DIR_ORIGINAL].bytes + | 98 | bytes = counters[IP_CT_DIR_ORIGINAL].bytes + |
100 | ct->counters[IP_CT_DIR_REPLY].bytes; | 99 | counters[IP_CT_DIR_REPLY].bytes; |
101 | pkts = ct->counters[IP_CT_DIR_ORIGINAL].packets+ | 100 | pkts = counters[IP_CT_DIR_ORIGINAL].packets+ |
102 | ct->counters[IP_CT_DIR_REPLY].packets; | 101 | counters[IP_CT_DIR_REPLY].packets; |
103 | 102 | ||
104 | /* FIXME_THEORETICAL: what to do if sum | 103 | /* FIXME_THEORETICAL: what to do if sum |
105 | * overflows ? */ | 104 | * overflows ? */ |
diff --git a/net/ipv4/netfilter/ipt_connmark.c b/net/ipv4/netfilter/ipt_connmark.c index bf8de47ce004..5306ef293b92 100644 --- a/net/ipv4/netfilter/ipt_connmark.c +++ b/net/ipv4/netfilter/ipt_connmark.c | |||
@@ -28,7 +28,7 @@ MODULE_LICENSE("GPL"); | |||
28 | 28 | ||
29 | #include <linux/netfilter_ipv4/ip_tables.h> | 29 | #include <linux/netfilter_ipv4/ip_tables.h> |
30 | #include <linux/netfilter_ipv4/ipt_connmark.h> | 30 | #include <linux/netfilter_ipv4/ipt_connmark.h> |
31 | #include <linux/netfilter_ipv4/ip_conntrack.h> | 31 | #include <net/netfilter/nf_conntrack_compat.h> |
32 | 32 | ||
33 | static int | 33 | static int |
34 | match(const struct sk_buff *skb, | 34 | match(const struct sk_buff *skb, |
@@ -39,12 +39,12 @@ match(const struct sk_buff *skb, | |||
39 | int *hotdrop) | 39 | int *hotdrop) |
40 | { | 40 | { |
41 | const struct ipt_connmark_info *info = matchinfo; | 41 | const struct ipt_connmark_info *info = matchinfo; |
42 | enum ip_conntrack_info ctinfo; | 42 | u_int32_t ctinfo; |
43 | struct ip_conntrack *ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); | 43 | const u_int32_t *ctmark = nf_ct_get_mark(skb, &ctinfo); |
44 | if (!ct) | 44 | if (!ctmark) |
45 | return 0; | 45 | return 0; |
46 | 46 | ||
47 | return ((ct->mark & info->mask) == info->mark) ^ info->invert; | 47 | return (((*ctmark) & info->mask) == info->mark) ^ info->invert; |
48 | } | 48 | } |
49 | 49 | ||
50 | static int | 50 | static int |
diff --git a/net/ipv4/netfilter/ipt_conntrack.c b/net/ipv4/netfilter/ipt_conntrack.c index c1d22801b7cf..c8d18705469b 100644 --- a/net/ipv4/netfilter/ipt_conntrack.c +++ b/net/ipv4/netfilter/ipt_conntrack.c | |||
@@ -10,7 +10,14 @@ | |||
10 | 10 | ||
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/skbuff.h> | 12 | #include <linux/skbuff.h> |
13 | |||
14 | #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) | ||
13 | #include <linux/netfilter_ipv4/ip_conntrack.h> | 15 | #include <linux/netfilter_ipv4/ip_conntrack.h> |
16 | #include <linux/netfilter_ipv4/ip_conntrack_tuple.h> | ||
17 | #else | ||
18 | #include <net/netfilter/nf_conntrack.h> | ||
19 | #endif | ||
20 | |||
14 | #include <linux/netfilter_ipv4/ip_tables.h> | 21 | #include <linux/netfilter_ipv4/ip_tables.h> |
15 | #include <linux/netfilter_ipv4/ipt_conntrack.h> | 22 | #include <linux/netfilter_ipv4/ipt_conntrack.h> |
16 | 23 | ||
@@ -18,6 +25,8 @@ MODULE_LICENSE("GPL"); | |||
18 | MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>"); | 25 | MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>"); |
19 | MODULE_DESCRIPTION("iptables connection tracking match module"); | 26 | MODULE_DESCRIPTION("iptables connection tracking match module"); |
20 | 27 | ||
28 | #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) | ||
29 | |||
21 | static int | 30 | static int |
22 | match(const struct sk_buff *skb, | 31 | match(const struct sk_buff *skb, |
23 | const struct net_device *in, | 32 | const struct net_device *in, |
@@ -102,6 +111,93 @@ match(const struct sk_buff *skb, | |||
102 | return 1; | 111 | return 1; |
103 | } | 112 | } |
104 | 113 | ||
114 | #else /* CONFIG_IP_NF_CONNTRACK */ | ||
115 | static int | ||
116 | match(const struct sk_buff *skb, | ||
117 | const struct net_device *in, | ||
118 | const struct net_device *out, | ||
119 | const void *matchinfo, | ||
120 | int offset, | ||
121 | int *hotdrop) | ||
122 | { | ||
123 | const struct ipt_conntrack_info *sinfo = matchinfo; | ||
124 | struct nf_conn *ct; | ||
125 | enum ip_conntrack_info ctinfo; | ||
126 | unsigned int statebit; | ||
127 | |||
128 | ct = nf_ct_get((struct sk_buff *)skb, &ctinfo); | ||
129 | |||
130 | #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg)) | ||
131 | |||
132 | if (ct == &nf_conntrack_untracked) | ||
133 | statebit = IPT_CONNTRACK_STATE_UNTRACKED; | ||
134 | else if (ct) | ||
135 | statebit = IPT_CONNTRACK_STATE_BIT(ctinfo); | ||
136 | else | ||
137 | statebit = IPT_CONNTRACK_STATE_INVALID; | ||
138 | |||
139 | if(sinfo->flags & IPT_CONNTRACK_STATE) { | ||
140 | if (ct) { | ||
141 | if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip != | ||
142 | ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip) | ||
143 | statebit |= IPT_CONNTRACK_STATE_SNAT; | ||
144 | |||
145 | if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip != | ||
146 | ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip) | ||
147 | statebit |= IPT_CONNTRACK_STATE_DNAT; | ||
148 | } | ||
149 | |||
150 | if (FWINV((statebit & sinfo->statemask) == 0, IPT_CONNTRACK_STATE)) | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | if(sinfo->flags & IPT_CONNTRACK_PROTO) { | ||
155 | if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, IPT_CONNTRACK_PROTO)) | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | if(sinfo->flags & IPT_CONNTRACK_ORIGSRC) { | ||
160 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, IPT_CONNTRACK_ORIGSRC)) | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | if(sinfo->flags & IPT_CONNTRACK_ORIGDST) { | ||
165 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, IPT_CONNTRACK_ORIGDST)) | ||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | if(sinfo->flags & IPT_CONNTRACK_REPLSRC) { | ||
170 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, IPT_CONNTRACK_REPLSRC)) | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | if(sinfo->flags & IPT_CONNTRACK_REPLDST) { | ||
175 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, IPT_CONNTRACK_REPLDST)) | ||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | if(sinfo->flags & IPT_CONNTRACK_STATUS) { | ||
180 | if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, IPT_CONNTRACK_STATUS)) | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | if(sinfo->flags & IPT_CONNTRACK_EXPIRES) { | ||
185 | unsigned long expires; | ||
186 | |||
187 | if(!ct) | ||
188 | return 0; | ||
189 | |||
190 | expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0; | ||
191 | |||
192 | if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), IPT_CONNTRACK_EXPIRES)) | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | return 1; | ||
197 | } | ||
198 | |||
199 | #endif /* CONFIG_NF_IP_CONNTRACK */ | ||
200 | |||
105 | static int check(const char *tablename, | 201 | static int check(const char *tablename, |
106 | const struct ipt_ip *ip, | 202 | const struct ipt_ip *ip, |
107 | void *matchinfo, | 203 | void *matchinfo, |
diff --git a/net/ipv4/netfilter/ipt_helper.c b/net/ipv4/netfilter/ipt_helper.c index 3e7dd014de43..bf14e1c7798a 100644 --- a/net/ipv4/netfilter/ipt_helper.c +++ b/net/ipv4/netfilter/ipt_helper.c | |||
@@ -13,9 +13,15 @@ | |||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/skbuff.h> | 14 | #include <linux/skbuff.h> |
15 | #include <linux/netfilter.h> | 15 | #include <linux/netfilter.h> |
16 | #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) | ||
16 | #include <linux/netfilter_ipv4/ip_conntrack.h> | 17 | #include <linux/netfilter_ipv4/ip_conntrack.h> |
17 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> | 18 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> |
18 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | 19 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> |
20 | #else | ||
21 | #include <net/netfilter/nf_conntrack.h> | ||
22 | #include <net/netfilter/nf_conntrack_core.h> | ||
23 | #include <net/netfilter/nf_conntrack_helper.h> | ||
24 | #endif | ||
19 | #include <linux/netfilter_ipv4/ip_tables.h> | 25 | #include <linux/netfilter_ipv4/ip_tables.h> |
20 | #include <linux/netfilter_ipv4/ipt_helper.h> | 26 | #include <linux/netfilter_ipv4/ipt_helper.h> |
21 | 27 | ||
@@ -29,6 +35,7 @@ MODULE_DESCRIPTION("iptables helper match module"); | |||
29 | #define DEBUGP(format, args...) | 35 | #define DEBUGP(format, args...) |
30 | #endif | 36 | #endif |
31 | 37 | ||
38 | #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) | ||
32 | static int | 39 | static int |
33 | match(const struct sk_buff *skb, | 40 | match(const struct sk_buff *skb, |
34 | const struct net_device *in, | 41 | const struct net_device *in, |
@@ -73,6 +80,53 @@ out_unlock: | |||
73 | return ret; | 80 | return ret; |
74 | } | 81 | } |
75 | 82 | ||
83 | #else /* CONFIG_IP_NF_CONNTRACK */ | ||
84 | |||
85 | static int | ||
86 | match(const struct sk_buff *skb, | ||
87 | const struct net_device *in, | ||
88 | const struct net_device *out, | ||
89 | const void *matchinfo, | ||
90 | int offset, | ||
91 | int *hotdrop) | ||
92 | { | ||
93 | const struct ipt_helper_info *info = matchinfo; | ||
94 | struct nf_conn *ct; | ||
95 | enum ip_conntrack_info ctinfo; | ||
96 | int ret = info->invert; | ||
97 | |||
98 | ct = nf_ct_get((struct sk_buff *)skb, &ctinfo); | ||
99 | if (!ct) { | ||
100 | DEBUGP("ipt_helper: Eek! invalid conntrack?\n"); | ||
101 | return ret; | ||
102 | } | ||
103 | |||
104 | if (!ct->master) { | ||
105 | DEBUGP("ipt_helper: conntrack %p has no master\n", ct); | ||
106 | return ret; | ||
107 | } | ||
108 | |||
109 | read_lock_bh(&nf_conntrack_lock); | ||
110 | if (!ct->master->helper) { | ||
111 | DEBUGP("ipt_helper: master ct %p has no helper\n", | ||
112 | exp->expectant); | ||
113 | goto out_unlock; | ||
114 | } | ||
115 | |||
116 | DEBUGP("master's name = %s , info->name = %s\n", | ||
117 | ct->master->helper->name, info->name); | ||
118 | |||
119 | if (info->name[0] == '\0') | ||
120 | ret ^= 1; | ||
121 | else | ||
122 | ret ^= !strncmp(ct->master->helper->name, info->name, | ||
123 | strlen(ct->master->helper->name)); | ||
124 | out_unlock: | ||
125 | read_unlock_bh(&nf_conntrack_lock); | ||
126 | return ret; | ||
127 | } | ||
128 | #endif | ||
129 | |||
76 | static int check(const char *tablename, | 130 | static int check(const char *tablename, |
77 | const struct ipt_ip *ip, | 131 | const struct ipt_ip *ip, |
78 | void *matchinfo, | 132 | void *matchinfo, |
diff --git a/net/ipv4/netfilter/ipt_state.c b/net/ipv4/netfilter/ipt_state.c index b1511b97ea5f..4d7f16b70cec 100644 --- a/net/ipv4/netfilter/ipt_state.c +++ b/net/ipv4/netfilter/ipt_state.c | |||
@@ -10,7 +10,7 @@ | |||
10 | 10 | ||
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/skbuff.h> | 12 | #include <linux/skbuff.h> |
13 | #include <linux/netfilter_ipv4/ip_conntrack.h> | 13 | #include <net/netfilter/nf_conntrack_compat.h> |
14 | #include <linux/netfilter_ipv4/ip_tables.h> | 14 | #include <linux/netfilter_ipv4/ip_tables.h> |
15 | #include <linux/netfilter_ipv4/ipt_state.h> | 15 | #include <linux/netfilter_ipv4/ipt_state.h> |
16 | 16 | ||
@@ -30,9 +30,9 @@ match(const struct sk_buff *skb, | |||
30 | enum ip_conntrack_info ctinfo; | 30 | enum ip_conntrack_info ctinfo; |
31 | unsigned int statebit; | 31 | unsigned int statebit; |
32 | 32 | ||
33 | if (skb->nfct == &ip_conntrack_untracked.ct_general) | 33 | if (nf_ct_is_untracked(skb)) |
34 | statebit = IPT_STATE_UNTRACKED; | 34 | statebit = IPT_STATE_UNTRACKED; |
35 | else if (!ip_conntrack_get(skb, &ctinfo)) | 35 | else if (!nf_ct_get_ctinfo(skb, &ctinfo)) |
36 | statebit = IPT_STATE_INVALID; | 36 | statebit = IPT_STATE_INVALID; |
37 | else | 37 | else |
38 | statebit = IPT_STATE_BIT(ctinfo); | 38 | statebit = IPT_STATE_BIT(ctinfo); |
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c new file mode 100644 index 000000000000..8202c1c0afad --- /dev/null +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | |||
@@ -0,0 +1,571 @@ | |||
1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
9 | * - move L3 protocol dependent part to this file. | ||
10 | * 23 Mar 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
11 | * - add get_features() to support various size of conntrack | ||
12 | * structures. | ||
13 | * | ||
14 | * Derived from net/ipv4/netfilter/ip_conntrack_standalone.c | ||
15 | */ | ||
16 | |||
17 | #include <linux/config.h> | ||
18 | #include <linux/types.h> | ||
19 | #include <linux/ip.h> | ||
20 | #include <linux/netfilter.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/skbuff.h> | ||
23 | #include <linux/icmp.h> | ||
24 | #include <linux/sysctl.h> | ||
25 | #include <net/ip.h> | ||
26 | |||
27 | #include <linux/netfilter_ipv4.h> | ||
28 | #include <net/netfilter/nf_conntrack.h> | ||
29 | #include <net/netfilter/nf_conntrack_helper.h> | ||
30 | #include <net/netfilter/nf_conntrack_protocol.h> | ||
31 | #include <net/netfilter/nf_conntrack_l3proto.h> | ||
32 | #include <net/netfilter/nf_conntrack_core.h> | ||
33 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> | ||
34 | |||
35 | #if 0 | ||
36 | #define DEBUGP printk | ||
37 | #else | ||
38 | #define DEBUGP(format, args...) | ||
39 | #endif | ||
40 | |||
41 | DECLARE_PER_CPU(struct nf_conntrack_stat, nf_conntrack_stat); | ||
42 | |||
43 | static int ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, | ||
44 | struct nf_conntrack_tuple *tuple) | ||
45 | { | ||
46 | u_int32_t _addrs[2], *ap; | ||
47 | ap = skb_header_pointer(skb, nhoff + offsetof(struct iphdr, saddr), | ||
48 | sizeof(u_int32_t) * 2, _addrs); | ||
49 | if (ap == NULL) | ||
50 | return 0; | ||
51 | |||
52 | tuple->src.u3.ip = ap[0]; | ||
53 | tuple->dst.u3.ip = ap[1]; | ||
54 | |||
55 | return 1; | ||
56 | } | ||
57 | |||
58 | static int ipv4_invert_tuple(struct nf_conntrack_tuple *tuple, | ||
59 | const struct nf_conntrack_tuple *orig) | ||
60 | { | ||
61 | tuple->src.u3.ip = orig->dst.u3.ip; | ||
62 | tuple->dst.u3.ip = orig->src.u3.ip; | ||
63 | |||
64 | return 1; | ||
65 | } | ||
66 | |||
67 | static int ipv4_print_tuple(struct seq_file *s, | ||
68 | const struct nf_conntrack_tuple *tuple) | ||
69 | { | ||
70 | return seq_printf(s, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", | ||
71 | NIPQUAD(tuple->src.u3.ip), | ||
72 | NIPQUAD(tuple->dst.u3.ip)); | ||
73 | } | ||
74 | |||
75 | static int ipv4_print_conntrack(struct seq_file *s, | ||
76 | const struct nf_conn *conntrack) | ||
77 | { | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | /* Returns new sk_buff, or NULL */ | ||
82 | static struct sk_buff * | ||
83 | nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user) | ||
84 | { | ||
85 | skb_orphan(skb); | ||
86 | |||
87 | local_bh_disable(); | ||
88 | skb = ip_defrag(skb, user); | ||
89 | local_bh_enable(); | ||
90 | |||
91 | if (skb) | ||
92 | ip_send_check(skb->nh.iph); | ||
93 | |||
94 | return skb; | ||
95 | } | ||
96 | |||
97 | static int | ||
98 | ipv4_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff, | ||
99 | u_int8_t *protonum) | ||
100 | { | ||
101 | /* Never happen */ | ||
102 | if ((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) { | ||
103 | if (net_ratelimit()) { | ||
104 | printk(KERN_ERR "ipv4_prepare: Frag of proto %u (hook=%u)\n", | ||
105 | (*pskb)->nh.iph->protocol, hooknum); | ||
106 | } | ||
107 | return -NF_DROP; | ||
108 | } | ||
109 | |||
110 | *dataoff = (*pskb)->nh.raw - (*pskb)->data + (*pskb)->nh.iph->ihl*4; | ||
111 | *protonum = (*pskb)->nh.iph->protocol; | ||
112 | |||
113 | return NF_ACCEPT; | ||
114 | } | ||
115 | |||
116 | int nat_module_is_loaded = 0; | ||
117 | static u_int32_t ipv4_get_features(const struct nf_conntrack_tuple *tuple) | ||
118 | { | ||
119 | if (nat_module_is_loaded) | ||
120 | return NF_CT_F_NAT; | ||
121 | |||
122 | return NF_CT_F_BASIC; | ||
123 | } | ||
124 | |||
125 | static unsigned int ipv4_confirm(unsigned int hooknum, | ||
126 | struct sk_buff **pskb, | ||
127 | const struct net_device *in, | ||
128 | const struct net_device *out, | ||
129 | int (*okfn)(struct sk_buff *)) | ||
130 | { | ||
131 | /* We've seen it coming out the other side: confirm it */ | ||
132 | return nf_conntrack_confirm(pskb); | ||
133 | } | ||
134 | |||
135 | static unsigned int ipv4_conntrack_help(unsigned int hooknum, | ||
136 | struct sk_buff **pskb, | ||
137 | const struct net_device *in, | ||
138 | const struct net_device *out, | ||
139 | int (*okfn)(struct sk_buff *)) | ||
140 | { | ||
141 | struct nf_conn *ct; | ||
142 | enum ip_conntrack_info ctinfo; | ||
143 | |||
144 | /* This is where we call the helper: as the packet goes out. */ | ||
145 | ct = nf_ct_get(*pskb, &ctinfo); | ||
146 | if (ct && ct->helper) { | ||
147 | unsigned int ret; | ||
148 | ret = ct->helper->help(pskb, | ||
149 | (*pskb)->nh.raw - (*pskb)->data | ||
150 | + (*pskb)->nh.iph->ihl*4, | ||
151 | ct, ctinfo); | ||
152 | if (ret != NF_ACCEPT) | ||
153 | return ret; | ||
154 | } | ||
155 | return NF_ACCEPT; | ||
156 | } | ||
157 | |||
158 | static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, | ||
159 | struct sk_buff **pskb, | ||
160 | const struct net_device *in, | ||
161 | const struct net_device *out, | ||
162 | int (*okfn)(struct sk_buff *)) | ||
163 | { | ||
164 | #if !defined(CONFIG_IP_NF_NAT) && !defined(CONFIG_IP_NF_NAT_MODULE) | ||
165 | /* Previously seen (loopback)? Ignore. Do this before | ||
166 | fragment check. */ | ||
167 | if ((*pskb)->nfct) | ||
168 | return NF_ACCEPT; | ||
169 | #endif | ||
170 | |||
171 | /* Gather fragments. */ | ||
172 | if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) { | ||
173 | *pskb = nf_ct_ipv4_gather_frags(*pskb, | ||
174 | hooknum == NF_IP_PRE_ROUTING ? | ||
175 | IP_DEFRAG_CONNTRACK_IN : | ||
176 | IP_DEFRAG_CONNTRACK_OUT); | ||
177 | if (!*pskb) | ||
178 | return NF_STOLEN; | ||
179 | } | ||
180 | return NF_ACCEPT; | ||
181 | } | ||
182 | |||
183 | static unsigned int ipv4_refrag(unsigned int hooknum, | ||
184 | struct sk_buff **pskb, | ||
185 | const struct net_device *in, | ||
186 | const struct net_device *out, | ||
187 | int (*okfn)(struct sk_buff *)) | ||
188 | { | ||
189 | struct rtable *rt = (struct rtable *)(*pskb)->dst; | ||
190 | |||
191 | /* We've seen it coming out the other side: confirm */ | ||
192 | if (ipv4_confirm(hooknum, pskb, in, out, okfn) != NF_ACCEPT) | ||
193 | return NF_DROP; | ||
194 | |||
195 | /* Local packets are never produced too large for their | ||
196 | interface. We degfragment them at LOCAL_OUT, however, | ||
197 | so we have to refragment them here. */ | ||
198 | if ((*pskb)->len > dst_mtu(&rt->u.dst) && | ||
199 | !skb_shinfo(*pskb)->tso_size) { | ||
200 | /* No hook can be after us, so this should be OK. */ | ||
201 | ip_fragment(*pskb, okfn); | ||
202 | return NF_STOLEN; | ||
203 | } | ||
204 | return NF_ACCEPT; | ||
205 | } | ||
206 | |||
207 | static unsigned int ipv4_conntrack_in(unsigned int hooknum, | ||
208 | struct sk_buff **pskb, | ||
209 | const struct net_device *in, | ||
210 | const struct net_device *out, | ||
211 | int (*okfn)(struct sk_buff *)) | ||
212 | { | ||
213 | return nf_conntrack_in(PF_INET, hooknum, pskb); | ||
214 | } | ||
215 | |||
216 | static unsigned int ipv4_conntrack_local(unsigned int hooknum, | ||
217 | struct sk_buff **pskb, | ||
218 | const struct net_device *in, | ||
219 | const struct net_device *out, | ||
220 | int (*okfn)(struct sk_buff *)) | ||
221 | { | ||
222 | /* root is playing with raw sockets. */ | ||
223 | if ((*pskb)->len < sizeof(struct iphdr) | ||
224 | || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) { | ||
225 | if (net_ratelimit()) | ||
226 | printk("ipt_hook: happy cracking.\n"); | ||
227 | return NF_ACCEPT; | ||
228 | } | ||
229 | return nf_conntrack_in(PF_INET, hooknum, pskb); | ||
230 | } | ||
231 | |||
232 | /* Connection tracking may drop packets, but never alters them, so | ||
233 | make it the first hook. */ | ||
234 | static struct nf_hook_ops ipv4_conntrack_defrag_ops = { | ||
235 | .hook = ipv4_conntrack_defrag, | ||
236 | .owner = THIS_MODULE, | ||
237 | .pf = PF_INET, | ||
238 | .hooknum = NF_IP_PRE_ROUTING, | ||
239 | .priority = NF_IP_PRI_CONNTRACK_DEFRAG, | ||
240 | }; | ||
241 | |||
242 | static struct nf_hook_ops ipv4_conntrack_in_ops = { | ||
243 | .hook = ipv4_conntrack_in, | ||
244 | .owner = THIS_MODULE, | ||
245 | .pf = PF_INET, | ||
246 | .hooknum = NF_IP_PRE_ROUTING, | ||
247 | .priority = NF_IP_PRI_CONNTRACK, | ||
248 | }; | ||
249 | |||
250 | static struct nf_hook_ops ipv4_conntrack_defrag_local_out_ops = { | ||
251 | .hook = ipv4_conntrack_defrag, | ||
252 | .owner = THIS_MODULE, | ||
253 | .pf = PF_INET, | ||
254 | .hooknum = NF_IP_LOCAL_OUT, | ||
255 | .priority = NF_IP_PRI_CONNTRACK_DEFRAG, | ||
256 | }; | ||
257 | |||
258 | static struct nf_hook_ops ipv4_conntrack_local_out_ops = { | ||
259 | .hook = ipv4_conntrack_local, | ||
260 | .owner = THIS_MODULE, | ||
261 | .pf = PF_INET, | ||
262 | .hooknum = NF_IP_LOCAL_OUT, | ||
263 | .priority = NF_IP_PRI_CONNTRACK, | ||
264 | }; | ||
265 | |||
266 | /* helpers */ | ||
267 | static struct nf_hook_ops ipv4_conntrack_helper_out_ops = { | ||
268 | .hook = ipv4_conntrack_help, | ||
269 | .owner = THIS_MODULE, | ||
270 | .pf = PF_INET, | ||
271 | .hooknum = NF_IP_POST_ROUTING, | ||
272 | .priority = NF_IP_PRI_CONNTRACK_HELPER, | ||
273 | }; | ||
274 | |||
275 | static struct nf_hook_ops ipv4_conntrack_helper_in_ops = { | ||
276 | .hook = ipv4_conntrack_help, | ||
277 | .owner = THIS_MODULE, | ||
278 | .pf = PF_INET, | ||
279 | .hooknum = NF_IP_LOCAL_IN, | ||
280 | .priority = NF_IP_PRI_CONNTRACK_HELPER, | ||
281 | }; | ||
282 | |||
283 | |||
284 | /* Refragmenter; last chance. */ | ||
285 | static struct nf_hook_ops ipv4_conntrack_out_ops = { | ||
286 | .hook = ipv4_refrag, | ||
287 | .owner = THIS_MODULE, | ||
288 | .pf = PF_INET, | ||
289 | .hooknum = NF_IP_POST_ROUTING, | ||
290 | .priority = NF_IP_PRI_CONNTRACK_CONFIRM, | ||
291 | }; | ||
292 | |||
293 | static struct nf_hook_ops ipv4_conntrack_local_in_ops = { | ||
294 | .hook = ipv4_confirm, | ||
295 | .owner = THIS_MODULE, | ||
296 | .pf = PF_INET, | ||
297 | .hooknum = NF_IP_LOCAL_IN, | ||
298 | .priority = NF_IP_PRI_CONNTRACK_CONFIRM, | ||
299 | }; | ||
300 | |||
301 | #ifdef CONFIG_SYSCTL | ||
302 | /* From nf_conntrack_proto_icmp.c */ | ||
303 | extern unsigned long nf_ct_icmp_timeout; | ||
304 | static struct ctl_table_header *nf_ct_ipv4_sysctl_header; | ||
305 | |||
306 | static ctl_table nf_ct_sysctl_table[] = { | ||
307 | { | ||
308 | .ctl_name = NET_NF_CONNTRACK_ICMP_TIMEOUT, | ||
309 | .procname = "nf_conntrack_icmp_timeout", | ||
310 | .data = &nf_ct_icmp_timeout, | ||
311 | .maxlen = sizeof(unsigned int), | ||
312 | .mode = 0644, | ||
313 | .proc_handler = &proc_dointvec_jiffies, | ||
314 | }, | ||
315 | { .ctl_name = 0 } | ||
316 | }; | ||
317 | |||
318 | static ctl_table nf_ct_netfilter_table[] = { | ||
319 | { | ||
320 | .ctl_name = NET_NETFILTER, | ||
321 | .procname = "netfilter", | ||
322 | .mode = 0555, | ||
323 | .child = nf_ct_sysctl_table, | ||
324 | }, | ||
325 | { .ctl_name = 0 } | ||
326 | }; | ||
327 | |||
328 | static ctl_table nf_ct_net_table[] = { | ||
329 | { | ||
330 | .ctl_name = CTL_NET, | ||
331 | .procname = "net", | ||
332 | .mode = 0555, | ||
333 | .child = nf_ct_netfilter_table, | ||
334 | }, | ||
335 | { .ctl_name = 0 } | ||
336 | }; | ||
337 | #endif | ||
338 | |||
339 | /* Fast function for those who don't want to parse /proc (and I don't | ||
340 | blame them). */ | ||
341 | /* Reversing the socket's dst/src point of view gives us the reply | ||
342 | mapping. */ | ||
343 | static int | ||
344 | getorigdst(struct sock *sk, int optval, void __user *user, int *len) | ||
345 | { | ||
346 | struct inet_sock *inet = inet_sk(sk); | ||
347 | struct nf_conntrack_tuple_hash *h; | ||
348 | struct nf_conntrack_tuple tuple; | ||
349 | |||
350 | NF_CT_TUPLE_U_BLANK(&tuple); | ||
351 | tuple.src.u3.ip = inet->rcv_saddr; | ||
352 | tuple.src.u.tcp.port = inet->sport; | ||
353 | tuple.dst.u3.ip = inet->daddr; | ||
354 | tuple.dst.u.tcp.port = inet->dport; | ||
355 | tuple.src.l3num = PF_INET; | ||
356 | tuple.dst.protonum = IPPROTO_TCP; | ||
357 | |||
358 | /* We only do TCP at the moment: is there a better way? */ | ||
359 | if (strcmp(sk->sk_prot->name, "TCP")) { | ||
360 | DEBUGP("SO_ORIGINAL_DST: Not a TCP socket\n"); | ||
361 | return -ENOPROTOOPT; | ||
362 | } | ||
363 | |||
364 | if ((unsigned int) *len < sizeof(struct sockaddr_in)) { | ||
365 | DEBUGP("SO_ORIGINAL_DST: len %u not %u\n", | ||
366 | *len, sizeof(struct sockaddr_in)); | ||
367 | return -EINVAL; | ||
368 | } | ||
369 | |||
370 | h = nf_conntrack_find_get(&tuple, NULL); | ||
371 | if (h) { | ||
372 | struct sockaddr_in sin; | ||
373 | struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); | ||
374 | |||
375 | sin.sin_family = AF_INET; | ||
376 | sin.sin_port = ct->tuplehash[IP_CT_DIR_ORIGINAL] | ||
377 | .tuple.dst.u.tcp.port; | ||
378 | sin.sin_addr.s_addr = ct->tuplehash[IP_CT_DIR_ORIGINAL] | ||
379 | .tuple.dst.u3.ip; | ||
380 | |||
381 | DEBUGP("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n", | ||
382 | NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port)); | ||
383 | nf_ct_put(ct); | ||
384 | if (copy_to_user(user, &sin, sizeof(sin)) != 0) | ||
385 | return -EFAULT; | ||
386 | else | ||
387 | return 0; | ||
388 | } | ||
389 | DEBUGP("SO_ORIGINAL_DST: Can't find %u.%u.%u.%u/%u-%u.%u.%u.%u/%u.\n", | ||
390 | NIPQUAD(tuple.src.u3.ip), ntohs(tuple.src.u.tcp.port), | ||
391 | NIPQUAD(tuple.dst.u3.ip), ntohs(tuple.dst.u.tcp.port)); | ||
392 | return -ENOENT; | ||
393 | } | ||
394 | |||
395 | static struct nf_sockopt_ops so_getorigdst = { | ||
396 | .pf = PF_INET, | ||
397 | .get_optmin = SO_ORIGINAL_DST, | ||
398 | .get_optmax = SO_ORIGINAL_DST+1, | ||
399 | .get = &getorigdst, | ||
400 | }; | ||
401 | |||
402 | struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 = { | ||
403 | .l3proto = PF_INET, | ||
404 | .name = "ipv4", | ||
405 | .pkt_to_tuple = ipv4_pkt_to_tuple, | ||
406 | .invert_tuple = ipv4_invert_tuple, | ||
407 | .print_tuple = ipv4_print_tuple, | ||
408 | .print_conntrack = ipv4_print_conntrack, | ||
409 | .prepare = ipv4_prepare, | ||
410 | .get_features = ipv4_get_features, | ||
411 | .me = THIS_MODULE, | ||
412 | }; | ||
413 | |||
414 | extern struct nf_conntrack_protocol nf_conntrack_protocol_tcp4; | ||
415 | extern struct nf_conntrack_protocol nf_conntrack_protocol_udp4; | ||
416 | extern struct nf_conntrack_protocol nf_conntrack_protocol_icmp; | ||
417 | static int init_or_cleanup(int init) | ||
418 | { | ||
419 | int ret = 0; | ||
420 | |||
421 | if (!init) goto cleanup; | ||
422 | |||
423 | ret = nf_register_sockopt(&so_getorigdst); | ||
424 | if (ret < 0) { | ||
425 | printk(KERN_ERR "Unable to register netfilter socket option\n"); | ||
426 | goto cleanup_nothing; | ||
427 | } | ||
428 | |||
429 | ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_tcp4); | ||
430 | if (ret < 0) { | ||
431 | printk("nf_conntrack_ipv4: can't register tcp.\n"); | ||
432 | goto cleanup_sockopt; | ||
433 | } | ||
434 | |||
435 | ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_udp4); | ||
436 | if (ret < 0) { | ||
437 | printk("nf_conntrack_ipv4: can't register udp.\n"); | ||
438 | goto cleanup_tcp; | ||
439 | } | ||
440 | |||
441 | ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_icmp); | ||
442 | if (ret < 0) { | ||
443 | printk("nf_conntrack_ipv4: can't register icmp.\n"); | ||
444 | goto cleanup_udp; | ||
445 | } | ||
446 | |||
447 | ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv4); | ||
448 | if (ret < 0) { | ||
449 | printk("nf_conntrack_ipv4: can't register ipv4\n"); | ||
450 | goto cleanup_icmp; | ||
451 | } | ||
452 | |||
453 | ret = nf_register_hook(&ipv4_conntrack_defrag_ops); | ||
454 | if (ret < 0) { | ||
455 | printk("nf_conntrack_ipv4: can't register pre-routing defrag hook.\n"); | ||
456 | goto cleanup_ipv4; | ||
457 | } | ||
458 | ret = nf_register_hook(&ipv4_conntrack_defrag_local_out_ops); | ||
459 | if (ret < 0) { | ||
460 | printk("nf_conntrack_ipv4: can't register local_out defrag hook.\n"); | ||
461 | goto cleanup_defragops; | ||
462 | } | ||
463 | |||
464 | ret = nf_register_hook(&ipv4_conntrack_in_ops); | ||
465 | if (ret < 0) { | ||
466 | printk("nf_conntrack_ipv4: can't register pre-routing hook.\n"); | ||
467 | goto cleanup_defraglocalops; | ||
468 | } | ||
469 | |||
470 | ret = nf_register_hook(&ipv4_conntrack_local_out_ops); | ||
471 | if (ret < 0) { | ||
472 | printk("nf_conntrack_ipv4: can't register local out hook.\n"); | ||
473 | goto cleanup_inops; | ||
474 | } | ||
475 | |||
476 | ret = nf_register_hook(&ipv4_conntrack_helper_in_ops); | ||
477 | if (ret < 0) { | ||
478 | printk("nf_conntrack_ipv4: can't register local helper hook.\n"); | ||
479 | goto cleanup_inandlocalops; | ||
480 | } | ||
481 | |||
482 | ret = nf_register_hook(&ipv4_conntrack_helper_out_ops); | ||
483 | if (ret < 0) { | ||
484 | printk("nf_conntrack_ipv4: can't register postrouting helper hook.\n"); | ||
485 | goto cleanup_helperinops; | ||
486 | } | ||
487 | |||
488 | ret = nf_register_hook(&ipv4_conntrack_out_ops); | ||
489 | if (ret < 0) { | ||
490 | printk("nf_conntrack_ipv4: can't register post-routing hook.\n"); | ||
491 | goto cleanup_helperoutops; | ||
492 | } | ||
493 | |||
494 | ret = nf_register_hook(&ipv4_conntrack_local_in_ops); | ||
495 | if (ret < 0) { | ||
496 | printk("nf_conntrack_ipv4: can't register local in hook.\n"); | ||
497 | goto cleanup_inoutandlocalops; | ||
498 | } | ||
499 | |||
500 | #ifdef CONFIG_SYSCTL | ||
501 | nf_ct_ipv4_sysctl_header = register_sysctl_table(nf_ct_net_table, 0); | ||
502 | if (nf_ct_ipv4_sysctl_header == NULL) { | ||
503 | printk("nf_conntrack: can't register to sysctl.\n"); | ||
504 | ret = -ENOMEM; | ||
505 | goto cleanup_localinops; | ||
506 | } | ||
507 | #endif | ||
508 | |||
509 | /* For use by REJECT target */ | ||
510 | ip_ct_attach = __nf_conntrack_attach; | ||
511 | |||
512 | return ret; | ||
513 | |||
514 | cleanup: | ||
515 | synchronize_net(); | ||
516 | ip_ct_attach = NULL; | ||
517 | #ifdef CONFIG_SYSCTL | ||
518 | unregister_sysctl_table(nf_ct_ipv4_sysctl_header); | ||
519 | cleanup_localinops: | ||
520 | #endif | ||
521 | nf_unregister_hook(&ipv4_conntrack_local_in_ops); | ||
522 | cleanup_inoutandlocalops: | ||
523 | nf_unregister_hook(&ipv4_conntrack_out_ops); | ||
524 | cleanup_helperoutops: | ||
525 | nf_unregister_hook(&ipv4_conntrack_helper_out_ops); | ||
526 | cleanup_helperinops: | ||
527 | nf_unregister_hook(&ipv4_conntrack_helper_in_ops); | ||
528 | cleanup_inandlocalops: | ||
529 | nf_unregister_hook(&ipv4_conntrack_local_out_ops); | ||
530 | cleanup_inops: | ||
531 | nf_unregister_hook(&ipv4_conntrack_in_ops); | ||
532 | cleanup_defraglocalops: | ||
533 | nf_unregister_hook(&ipv4_conntrack_defrag_local_out_ops); | ||
534 | cleanup_defragops: | ||
535 | nf_unregister_hook(&ipv4_conntrack_defrag_ops); | ||
536 | cleanup_ipv4: | ||
537 | nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4); | ||
538 | cleanup_icmp: | ||
539 | nf_conntrack_protocol_unregister(&nf_conntrack_protocol_icmp); | ||
540 | cleanup_udp: | ||
541 | nf_conntrack_protocol_unregister(&nf_conntrack_protocol_udp4); | ||
542 | cleanup_tcp: | ||
543 | nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp4); | ||
544 | cleanup_sockopt: | ||
545 | nf_unregister_sockopt(&so_getorigdst); | ||
546 | cleanup_nothing: | ||
547 | return ret; | ||
548 | } | ||
549 | |||
550 | MODULE_LICENSE("GPL"); | ||
551 | |||
552 | static int __init init(void) | ||
553 | { | ||
554 | need_nf_conntrack(); | ||
555 | return init_or_cleanup(1); | ||
556 | } | ||
557 | |||
558 | static void __exit fini(void) | ||
559 | { | ||
560 | init_or_cleanup(0); | ||
561 | } | ||
562 | |||
563 | module_init(init); | ||
564 | module_exit(fini); | ||
565 | |||
566 | void need_ip_conntrack(void) | ||
567 | { | ||
568 | } | ||
569 | |||
570 | EXPORT_SYMBOL(need_ip_conntrack); | ||
571 | EXPORT_SYMBOL(nf_ct_ipv4_gather_frags); | ||
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c new file mode 100644 index 000000000000..7ddb5c08f7b8 --- /dev/null +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c | |||
@@ -0,0 +1,301 @@ | |||
1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
9 | * - enable working with Layer 3 protocol independent connection tracking. | ||
10 | * | ||
11 | * Derived from net/ipv4/netfilter/ip_conntrack_proto_icmp.c | ||
12 | */ | ||
13 | |||
14 | #include <linux/types.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <linux/timer.h> | ||
17 | #include <linux/netfilter.h> | ||
18 | #include <linux/in.h> | ||
19 | #include <linux/icmp.h> | ||
20 | #include <linux/seq_file.h> | ||
21 | #include <net/ip.h> | ||
22 | #include <net/checksum.h> | ||
23 | #include <linux/netfilter_ipv4.h> | ||
24 | #include <net/netfilter/nf_conntrack_tuple.h> | ||
25 | #include <net/netfilter/nf_conntrack_protocol.h> | ||
26 | #include <net/netfilter/nf_conntrack_core.h> | ||
27 | |||
28 | unsigned long nf_ct_icmp_timeout = 30*HZ; | ||
29 | |||
30 | #if 0 | ||
31 | #define DEBUGP printk | ||
32 | #else | ||
33 | #define DEBUGP(format, args...) | ||
34 | #endif | ||
35 | |||
36 | static int icmp_pkt_to_tuple(const struct sk_buff *skb, | ||
37 | unsigned int dataoff, | ||
38 | struct nf_conntrack_tuple *tuple) | ||
39 | { | ||
40 | struct icmphdr _hdr, *hp; | ||
41 | |||
42 | hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); | ||
43 | if (hp == NULL) | ||
44 | return 0; | ||
45 | |||
46 | tuple->dst.u.icmp.type = hp->type; | ||
47 | tuple->src.u.icmp.id = hp->un.echo.id; | ||
48 | tuple->dst.u.icmp.code = hp->code; | ||
49 | |||
50 | return 1; | ||
51 | } | ||
52 | |||
53 | static int icmp_invert_tuple(struct nf_conntrack_tuple *tuple, | ||
54 | const struct nf_conntrack_tuple *orig) | ||
55 | { | ||
56 | /* Add 1; spaces filled with 0. */ | ||
57 | static u_int8_t invmap[] | ||
58 | = { [ICMP_ECHO] = ICMP_ECHOREPLY + 1, | ||
59 | [ICMP_ECHOREPLY] = ICMP_ECHO + 1, | ||
60 | [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1, | ||
61 | [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1, | ||
62 | [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1, | ||
63 | [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1, | ||
64 | [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1, | ||
65 | [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1}; | ||
66 | |||
67 | if (orig->dst.u.icmp.type >= sizeof(invmap) | ||
68 | || !invmap[orig->dst.u.icmp.type]) | ||
69 | return 0; | ||
70 | |||
71 | tuple->src.u.icmp.id = orig->src.u.icmp.id; | ||
72 | tuple->dst.u.icmp.type = invmap[orig->dst.u.icmp.type] - 1; | ||
73 | tuple->dst.u.icmp.code = orig->dst.u.icmp.code; | ||
74 | return 1; | ||
75 | } | ||
76 | |||
77 | /* Print out the per-protocol part of the tuple. */ | ||
78 | static int icmp_print_tuple(struct seq_file *s, | ||
79 | const struct nf_conntrack_tuple *tuple) | ||
80 | { | ||
81 | return seq_printf(s, "type=%u code=%u id=%u ", | ||
82 | tuple->dst.u.icmp.type, | ||
83 | tuple->dst.u.icmp.code, | ||
84 | ntohs(tuple->src.u.icmp.id)); | ||
85 | } | ||
86 | |||
87 | /* Print out the private part of the conntrack. */ | ||
88 | static int icmp_print_conntrack(struct seq_file *s, | ||
89 | const struct nf_conn *conntrack) | ||
90 | { | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | /* Returns verdict for packet, or -1 for invalid. */ | ||
95 | static int icmp_packet(struct nf_conn *ct, | ||
96 | const struct sk_buff *skb, | ||
97 | unsigned int dataoff, | ||
98 | enum ip_conntrack_info ctinfo, | ||
99 | int pf, | ||
100 | unsigned int hooknum) | ||
101 | { | ||
102 | /* Try to delete connection immediately after all replies: | ||
103 | won't actually vanish as we still have skb, and del_timer | ||
104 | means this will only run once even if count hits zero twice | ||
105 | (theoretically possible with SMP) */ | ||
106 | if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) { | ||
107 | if (atomic_dec_and_test(&ct->proto.icmp.count) | ||
108 | && del_timer(&ct->timeout)) | ||
109 | ct->timeout.function((unsigned long)ct); | ||
110 | } else { | ||
111 | atomic_inc(&ct->proto.icmp.count); | ||
112 | nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb); | ||
113 | nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmp_timeout); | ||
114 | } | ||
115 | |||
116 | return NF_ACCEPT; | ||
117 | } | ||
118 | |||
119 | /* Called when a new connection for this protocol found. */ | ||
120 | static int icmp_new(struct nf_conn *conntrack, | ||
121 | const struct sk_buff *skb, unsigned int dataoff) | ||
122 | { | ||
123 | static u_int8_t valid_new[] | ||
124 | = { [ICMP_ECHO] = 1, | ||
125 | [ICMP_TIMESTAMP] = 1, | ||
126 | [ICMP_INFO_REQUEST] = 1, | ||
127 | [ICMP_ADDRESS] = 1 }; | ||
128 | |||
129 | if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new) | ||
130 | || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) { | ||
131 | /* Can't create a new ICMP `conn' with this. */ | ||
132 | DEBUGP("icmp: can't create new conn with type %u\n", | ||
133 | conntrack->tuplehash[0].tuple.dst.u.icmp.type); | ||
134 | NF_CT_DUMP_TUPLE(&conntrack->tuplehash[0].tuple); | ||
135 | return 0; | ||
136 | } | ||
137 | atomic_set(&conntrack->proto.icmp.count, 0); | ||
138 | return 1; | ||
139 | } | ||
140 | |||
141 | extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4; | ||
142 | /* Returns conntrack if it dealt with ICMP, and filled in skb fields */ | ||
143 | static int | ||
144 | icmp_error_message(struct sk_buff *skb, | ||
145 | enum ip_conntrack_info *ctinfo, | ||
146 | unsigned int hooknum) | ||
147 | { | ||
148 | struct nf_conntrack_tuple innertuple, origtuple; | ||
149 | struct { | ||
150 | struct icmphdr icmp; | ||
151 | struct iphdr ip; | ||
152 | } _in, *inside; | ||
153 | struct nf_conntrack_protocol *innerproto; | ||
154 | struct nf_conntrack_tuple_hash *h; | ||
155 | int dataoff; | ||
156 | |||
157 | NF_CT_ASSERT(skb->nfct == NULL); | ||
158 | |||
159 | /* Not enough header? */ | ||
160 | inside = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_in), &_in); | ||
161 | if (inside == NULL) | ||
162 | return -NF_ACCEPT; | ||
163 | |||
164 | /* Ignore ICMP's containing fragments (shouldn't happen) */ | ||
165 | if (inside->ip.frag_off & htons(IP_OFFSET)) { | ||
166 | DEBUGP("icmp_error_message: fragment of proto %u\n", | ||
167 | inside->ip.protocol); | ||
168 | return -NF_ACCEPT; | ||
169 | } | ||
170 | |||
171 | innerproto = nf_ct_find_proto(PF_INET, inside->ip.protocol); | ||
172 | dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp); | ||
173 | /* Are they talking about one of our connections? */ | ||
174 | if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside->ip.ihl*4, PF_INET, | ||
175 | inside->ip.protocol, &origtuple, | ||
176 | &nf_conntrack_l3proto_ipv4, innerproto)) { | ||
177 | DEBUGP("icmp_error_message: ! get_tuple p=%u", | ||
178 | inside->ip.protocol); | ||
179 | return -NF_ACCEPT; | ||
180 | } | ||
181 | |||
182 | /* Ordinarily, we'd expect the inverted tupleproto, but it's | ||
183 | been preserved inside the ICMP. */ | ||
184 | if (!nf_ct_invert_tuple(&innertuple, &origtuple, | ||
185 | &nf_conntrack_l3proto_ipv4, innerproto)) { | ||
186 | DEBUGP("icmp_error_message: no match\n"); | ||
187 | return -NF_ACCEPT; | ||
188 | } | ||
189 | |||
190 | *ctinfo = IP_CT_RELATED; | ||
191 | |||
192 | h = nf_conntrack_find_get(&innertuple, NULL); | ||
193 | if (!h) { | ||
194 | /* Locally generated ICMPs will match inverted if they | ||
195 | haven't been SNAT'ed yet */ | ||
196 | /* FIXME: NAT code has to handle half-done double NAT --RR */ | ||
197 | if (hooknum == NF_IP_LOCAL_OUT) | ||
198 | h = nf_conntrack_find_get(&origtuple, NULL); | ||
199 | |||
200 | if (!h) { | ||
201 | DEBUGP("icmp_error_message: no match\n"); | ||
202 | return -NF_ACCEPT; | ||
203 | } | ||
204 | |||
205 | /* Reverse direction from that found */ | ||
206 | if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) | ||
207 | *ctinfo += IP_CT_IS_REPLY; | ||
208 | } else { | ||
209 | if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) | ||
210 | *ctinfo += IP_CT_IS_REPLY; | ||
211 | } | ||
212 | |||
213 | /* Update skb to refer to this connection */ | ||
214 | skb->nfct = &nf_ct_tuplehash_to_ctrack(h)->ct_general; | ||
215 | skb->nfctinfo = *ctinfo; | ||
216 | return -NF_ACCEPT; | ||
217 | } | ||
218 | |||
219 | /* Small and modified version of icmp_rcv */ | ||
220 | static int | ||
221 | icmp_error(struct sk_buff *skb, unsigned int dataoff, | ||
222 | enum ip_conntrack_info *ctinfo, int pf, unsigned int hooknum) | ||
223 | { | ||
224 | struct icmphdr _ih, *icmph; | ||
225 | |||
226 | /* Not enough header? */ | ||
227 | icmph = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_ih), &_ih); | ||
228 | if (icmph == NULL) { | ||
229 | if (LOG_INVALID(IPPROTO_ICMP)) | ||
230 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, | ||
231 | "nf_ct_icmp: short packet "); | ||
232 | return -NF_ACCEPT; | ||
233 | } | ||
234 | |||
235 | /* See ip_conntrack_proto_tcp.c */ | ||
236 | if (hooknum != NF_IP_PRE_ROUTING) | ||
237 | goto checksum_skipped; | ||
238 | |||
239 | switch (skb->ip_summed) { | ||
240 | case CHECKSUM_HW: | ||
241 | if (!(u16)csum_fold(skb->csum)) | ||
242 | break; | ||
243 | if (LOG_INVALID(IPPROTO_ICMP)) | ||
244 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, | ||
245 | "nf_ct_icmp: bad HW ICMP checksum "); | ||
246 | return -NF_ACCEPT; | ||
247 | case CHECKSUM_NONE: | ||
248 | if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0))) { | ||
249 | if (LOG_INVALID(IPPROTO_ICMP)) | ||
250 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, | ||
251 | NULL, | ||
252 | "nf_ct_icmp: bad ICMP checksum "); | ||
253 | return -NF_ACCEPT; | ||
254 | } | ||
255 | default: | ||
256 | break; | ||
257 | } | ||
258 | |||
259 | checksum_skipped: | ||
260 | /* | ||
261 | * 18 is the highest 'known' ICMP type. Anything else is a mystery | ||
262 | * | ||
263 | * RFC 1122: 3.2.2 Unknown ICMP messages types MUST be silently | ||
264 | * discarded. | ||
265 | */ | ||
266 | if (icmph->type > NR_ICMP_TYPES) { | ||
267 | if (LOG_INVALID(IPPROTO_ICMP)) | ||
268 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, | ||
269 | "nf_ct_icmp: invalid ICMP type "); | ||
270 | return -NF_ACCEPT; | ||
271 | } | ||
272 | |||
273 | /* Need to track icmp error message? */ | ||
274 | if (icmph->type != ICMP_DEST_UNREACH | ||
275 | && icmph->type != ICMP_SOURCE_QUENCH | ||
276 | && icmph->type != ICMP_TIME_EXCEEDED | ||
277 | && icmph->type != ICMP_PARAMETERPROB | ||
278 | && icmph->type != ICMP_REDIRECT) | ||
279 | return NF_ACCEPT; | ||
280 | |||
281 | return icmp_error_message(skb, ctinfo, hooknum); | ||
282 | } | ||
283 | |||
284 | struct nf_conntrack_protocol nf_conntrack_protocol_icmp = | ||
285 | { | ||
286 | .list = { NULL, NULL }, | ||
287 | .l3proto = PF_INET, | ||
288 | .proto = IPPROTO_ICMP, | ||
289 | .name = "icmp", | ||
290 | .pkt_to_tuple = icmp_pkt_to_tuple, | ||
291 | .invert_tuple = icmp_invert_tuple, | ||
292 | .print_tuple = icmp_print_tuple, | ||
293 | .print_conntrack = icmp_print_conntrack, | ||
294 | .packet = icmp_packet, | ||
295 | .new = icmp_new, | ||
296 | .error = icmp_error, | ||
297 | .destroy = NULL, | ||
298 | .me = NULL | ||
299 | }; | ||
300 | |||
301 | EXPORT_SYMBOL(nf_conntrack_protocol_icmp); | ||
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 634dabb558fd..ac1fcf5b4ebc 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -1110,24 +1110,18 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) | |||
1110 | static int tcp_v4_checksum_init(struct sk_buff *skb) | 1110 | static int tcp_v4_checksum_init(struct sk_buff *skb) |
1111 | { | 1111 | { |
1112 | if (skb->ip_summed == CHECKSUM_HW) { | 1112 | if (skb->ip_summed == CHECKSUM_HW) { |
1113 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
1114 | if (!tcp_v4_check(skb->h.th, skb->len, skb->nh.iph->saddr, | 1113 | if (!tcp_v4_check(skb->h.th, skb->len, skb->nh.iph->saddr, |
1115 | skb->nh.iph->daddr, skb->csum)) | 1114 | skb->nh.iph->daddr, skb->csum)) { |
1115 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
1116 | return 0; | 1116 | return 0; |
1117 | 1117 | } | |
1118 | LIMIT_NETDEBUG(KERN_DEBUG "hw tcp v4 csum failed\n"); | ||
1119 | skb->ip_summed = CHECKSUM_NONE; | ||
1120 | } | 1118 | } |
1119 | |||
1120 | skb->csum = csum_tcpudp_nofold(skb->nh.iph->saddr, skb->nh.iph->daddr, | ||
1121 | skb->len, IPPROTO_TCP, 0); | ||
1122 | |||
1121 | if (skb->len <= 76) { | 1123 | if (skb->len <= 76) { |
1122 | if (tcp_v4_check(skb->h.th, skb->len, skb->nh.iph->saddr, | 1124 | return __skb_checksum_complete(skb); |
1123 | skb->nh.iph->daddr, | ||
1124 | skb_checksum(skb, 0, skb->len, 0))) | ||
1125 | return -1; | ||
1126 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
1127 | } else { | ||
1128 | skb->csum = ~tcp_v4_check(skb->h.th, skb->len, | ||
1129 | skb->nh.iph->saddr, | ||
1130 | skb->nh.iph->daddr, 0); | ||
1131 | } | 1125 | } |
1132 | return 0; | 1126 | return 0; |
1133 | } | 1127 | } |
@@ -1219,7 +1213,7 @@ int tcp_v4_rcv(struct sk_buff *skb) | |||
1219 | * provided case of th->doff==0 is elimineted. | 1213 | * provided case of th->doff==0 is elimineted. |
1220 | * So, we defer the checks. */ | 1214 | * So, we defer the checks. */ |
1221 | if ((skb->ip_summed != CHECKSUM_UNNECESSARY && | 1215 | if ((skb->ip_summed != CHECKSUM_UNNECESSARY && |
1222 | tcp_v4_checksum_init(skb) < 0)) | 1216 | tcp_v4_checksum_init(skb))) |
1223 | goto bad_packet; | 1217 | goto bad_packet; |
1224 | 1218 | ||
1225 | th = skb->h.th; | 1219 | th = skb->h.th; |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index e0bd1013cb0d..2422a5f7195d 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -761,7 +761,7 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
761 | 761 | ||
762 | static __inline__ int __udp_checksum_complete(struct sk_buff *skb) | 762 | static __inline__ int __udp_checksum_complete(struct sk_buff *skb) |
763 | { | 763 | { |
764 | return (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)); | 764 | return __skb_checksum_complete(skb); |
765 | } | 765 | } |
766 | 766 | ||
767 | static __inline__ int udp_checksum_complete(struct sk_buff *skb) | 767 | static __inline__ int udp_checksum_complete(struct sk_buff *skb) |
@@ -1100,11 +1100,8 @@ static int udp_checksum_init(struct sk_buff *skb, struct udphdr *uh, | |||
1100 | if (uh->check == 0) { | 1100 | if (uh->check == 0) { |
1101 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1101 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
1102 | } else if (skb->ip_summed == CHECKSUM_HW) { | 1102 | } else if (skb->ip_summed == CHECKSUM_HW) { |
1103 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
1104 | if (!udp_check(uh, ulen, saddr, daddr, skb->csum)) | 1103 | if (!udp_check(uh, ulen, saddr, daddr, skb->csum)) |
1105 | return 0; | 1104 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
1106 | LIMIT_NETDEBUG(KERN_DEBUG "udp v4 hw csum failure.\n"); | ||
1107 | skb->ip_summed = CHECKSUM_NONE; | ||
1108 | } | 1105 | } |
1109 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) | 1106 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) |
1110 | skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); | 1107 | skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); |
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 23e540365a14..1bdf0fb8bf8a 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
@@ -585,17 +585,16 @@ static int icmpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) | |||
585 | daddr = &skb->nh.ipv6h->daddr; | 585 | daddr = &skb->nh.ipv6h->daddr; |
586 | 586 | ||
587 | /* Perform checksum. */ | 587 | /* Perform checksum. */ |
588 | if (skb->ip_summed == CHECKSUM_HW) { | 588 | switch (skb->ip_summed) { |
589 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 589 | case CHECKSUM_HW: |
590 | if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, | 590 | if (!csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, |
591 | skb->csum)) { | 591 | skb->csum)) |
592 | LIMIT_NETDEBUG(KERN_DEBUG "ICMPv6 hw checksum failed\n"); | 592 | break; |
593 | skb->ip_summed = CHECKSUM_NONE; | 593 | /* fall through */ |
594 | } | 594 | case CHECKSUM_NONE: |
595 | } | 595 | skb->csum = ~csum_ipv6_magic(saddr, daddr, skb->len, |
596 | if (skb->ip_summed == CHECKSUM_NONE) { | 596 | IPPROTO_ICMPV6, 0); |
597 | if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, | 597 | if (__skb_checksum_complete(skb)) { |
598 | skb_checksum(skb, 0, skb->len, 0))) { | ||
599 | LIMIT_NETDEBUG(KERN_DEBUG "ICMPv6 checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n", | 598 | LIMIT_NETDEBUG(KERN_DEBUG "ICMPv6 checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n", |
600 | NIP6(*saddr), NIP6(*daddr)); | 599 | NIP6(*saddr), NIP6(*daddr)); |
601 | goto discard_it; | 600 | goto discard_it; |
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 6e3480426939..a6026d2787d2 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c | |||
@@ -176,6 +176,11 @@ resubmit: | |||
176 | if (ipprot->flags & INET6_PROTO_FINAL) { | 176 | if (ipprot->flags & INET6_PROTO_FINAL) { |
177 | struct ipv6hdr *hdr; | 177 | struct ipv6hdr *hdr; |
178 | 178 | ||
179 | /* Free reference early: we don't need it any more, | ||
180 | and it may hold ip_conntrack module loaded | ||
181 | indefinitely. */ | ||
182 | nf_reset(skb); | ||
183 | |||
179 | skb_postpull_rcsum(skb, skb->nh.raw, | 184 | skb_postpull_rcsum(skb, skb->nh.raw, |
180 | skb->h.raw - skb->nh.raw); | 185 | skb->h.raw - skb->nh.raw); |
181 | hdr = skb->nh.ipv6h; | 186 | hdr = skb->nh.ipv6h; |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index dbd9767b32e4..c1fa693511a1 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -441,9 +441,15 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from) | |||
441 | #ifdef CONFIG_NETFILTER | 441 | #ifdef CONFIG_NETFILTER |
442 | to->nfmark = from->nfmark; | 442 | to->nfmark = from->nfmark; |
443 | /* Connection association is same as pre-frag packet */ | 443 | /* Connection association is same as pre-frag packet */ |
444 | nf_conntrack_put(to->nfct); | ||
444 | to->nfct = from->nfct; | 445 | to->nfct = from->nfct; |
445 | nf_conntrack_get(to->nfct); | 446 | nf_conntrack_get(to->nfct); |
446 | to->nfctinfo = from->nfctinfo; | 447 | to->nfctinfo = from->nfctinfo; |
448 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | ||
449 | nf_conntrack_put_reasm(to->nfct_reasm); | ||
450 | to->nfct_reasm = from->nfct_reasm; | ||
451 | nf_conntrack_get_reasm(to->nfct_reasm); | ||
452 | #endif | ||
447 | #ifdef CONFIG_BRIDGE_NETFILTER | 453 | #ifdef CONFIG_BRIDGE_NETFILTER |
448 | nf_bridge_put(to->nf_bridge); | 454 | nf_bridge_put(to->nf_bridge); |
449 | to->nf_bridge = from->nf_bridge; | 455 | to->nf_bridge = from->nf_bridge; |
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index bb7ccfe33f23..971ba60bf6e9 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig | |||
@@ -278,5 +278,19 @@ config IP6_NF_RAW | |||
278 | If you want to compile it as a module, say M here and read | 278 | If you want to compile it as a module, say M here and read |
279 | <file:Documentation/modules.txt>. If unsure, say `N'. | 279 | <file:Documentation/modules.txt>. If unsure, say `N'. |
280 | 280 | ||
281 | config NF_CONNTRACK_IPV6 | ||
282 | tristate "IPv6 support for new connection tracking (EXPERIMENTAL)" | ||
283 | depends on EXPERIMENTAL && NF_CONNTRACK | ||
284 | ---help--- | ||
285 | Connection tracking keeps a record of what packets have passed | ||
286 | through your machine, in order to figure out how they are related | ||
287 | into connections. | ||
288 | |||
289 | This is IPv6 support on Layer 3 independent connection tracking. | ||
290 | Layer 3 independent connection tracking is experimental scheme | ||
291 | which generalize ip_conntrack to support other layer 3 protocols. | ||
292 | |||
293 | To compile it as a module, choose M here. If unsure, say N. | ||
294 | |||
281 | endmenu | 295 | endmenu |
282 | 296 | ||
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index 2b2c370e8b1c..9ab5b2ca1f59 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile | |||
@@ -27,3 +27,9 @@ obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o | |||
27 | obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o | 27 | obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o |
28 | obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o | 28 | obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o |
29 | obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o | 29 | obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o |
30 | |||
31 | # objects for l3 independent conntrack | ||
32 | nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o nf_conntrack_reasm.o | ||
33 | |||
34 | # l3 independent conntrack | ||
35 | obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o | ||
diff --git a/net/ipv6/netfilter/ip6t_MARK.c b/net/ipv6/netfilter/ip6t_MARK.c index 0c7584f92172..eab8fb864ee0 100644 --- a/net/ipv6/netfilter/ip6t_MARK.c +++ b/net/ipv6/netfilter/ip6t_MARK.c | |||
@@ -56,9 +56,9 @@ checkentry(const char *tablename, | |||
56 | return 1; | 56 | return 1; |
57 | } | 57 | } |
58 | 58 | ||
59 | static struct ip6t_target ip6t_mark_reg = { | 59 | static struct ip6t_target ip6t_mark_reg = { |
60 | .name = "MARK", | 60 | .name = "MARK", |
61 | .target = target, | 61 | .target = target, |
62 | .checkentry = checkentry, | 62 | .checkentry = checkentry, |
63 | .me = THIS_MODULE | 63 | .me = THIS_MODULE |
64 | }; | 64 | }; |
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c new file mode 100644 index 000000000000..e2c90b3a8074 --- /dev/null +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
@@ -0,0 +1,556 @@ | |||
1 | /* | ||
2 | * Copyright (C)2004 USAGI/WIDE Project | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * Author: | ||
9 | * Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
10 | * | ||
11 | * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
12 | * - support Layer 3 protocol independent connection tracking. | ||
13 | * Based on the original ip_conntrack code which had the following | ||
14 | * copyright information: | ||
15 | * (C) 1999-2001 Paul `Rusty' Russell | ||
16 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
17 | * | ||
18 | * 23 Mar 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
19 | * - add get_features() to support various size of conntrack | ||
20 | * structures. | ||
21 | */ | ||
22 | |||
23 | #include <linux/config.h> | ||
24 | #include <linux/types.h> | ||
25 | #include <linux/ipv6.h> | ||
26 | #include <linux/in6.h> | ||
27 | #include <linux/netfilter.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/skbuff.h> | ||
30 | #include <linux/icmp.h> | ||
31 | #include <linux/sysctl.h> | ||
32 | #include <net/ipv6.h> | ||
33 | |||
34 | #include <linux/netfilter_ipv6.h> | ||
35 | #include <net/netfilter/nf_conntrack.h> | ||
36 | #include <net/netfilter/nf_conntrack_helper.h> | ||
37 | #include <net/netfilter/nf_conntrack_protocol.h> | ||
38 | #include <net/netfilter/nf_conntrack_l3proto.h> | ||
39 | #include <net/netfilter/nf_conntrack_core.h> | ||
40 | |||
41 | #if 0 | ||
42 | #define DEBUGP printk | ||
43 | #else | ||
44 | #define DEBUGP(format, args...) | ||
45 | #endif | ||
46 | |||
47 | DECLARE_PER_CPU(struct ip_conntrack_stat, nf_conntrack_stat); | ||
48 | |||
49 | static int ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, | ||
50 | struct nf_conntrack_tuple *tuple) | ||
51 | { | ||
52 | u_int32_t _addrs[8], *ap; | ||
53 | |||
54 | ap = skb_header_pointer(skb, nhoff + offsetof(struct ipv6hdr, saddr), | ||
55 | sizeof(_addrs), _addrs); | ||
56 | if (ap == NULL) | ||
57 | return 0; | ||
58 | |||
59 | memcpy(tuple->src.u3.ip6, ap, sizeof(tuple->src.u3.ip6)); | ||
60 | memcpy(tuple->dst.u3.ip6, ap + 4, sizeof(tuple->dst.u3.ip6)); | ||
61 | |||
62 | return 1; | ||
63 | } | ||
64 | |||
65 | static int ipv6_invert_tuple(struct nf_conntrack_tuple *tuple, | ||
66 | const struct nf_conntrack_tuple *orig) | ||
67 | { | ||
68 | memcpy(tuple->src.u3.ip6, orig->dst.u3.ip6, sizeof(tuple->src.u3.ip6)); | ||
69 | memcpy(tuple->dst.u3.ip6, orig->src.u3.ip6, sizeof(tuple->dst.u3.ip6)); | ||
70 | |||
71 | return 1; | ||
72 | } | ||
73 | |||
74 | static int ipv6_print_tuple(struct seq_file *s, | ||
75 | const struct nf_conntrack_tuple *tuple) | ||
76 | { | ||
77 | return seq_printf(s, "src=%x:%x:%x:%x:%x:%x:%x:%x dst=%x:%x:%x:%x:%x:%x:%x:%x ", | ||
78 | NIP6(*((struct in6_addr *)tuple->src.u3.ip6)), | ||
79 | NIP6(*((struct in6_addr *)tuple->dst.u3.ip6))); | ||
80 | } | ||
81 | |||
82 | static int ipv6_print_conntrack(struct seq_file *s, | ||
83 | const struct nf_conn *conntrack) | ||
84 | { | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | /* | ||
89 | * Based on ipv6_skip_exthdr() in net/ipv6/exthdr.c | ||
90 | * | ||
91 | * This function parses (probably truncated) exthdr set "hdr" | ||
92 | * of length "len". "nexthdrp" initially points to some place, | ||
93 | * where type of the first header can be found. | ||
94 | * | ||
95 | * It skips all well-known exthdrs, and returns pointer to the start | ||
96 | * of unparsable area i.e. the first header with unknown type. | ||
97 | * if success, *nexthdr is updated by type/protocol of this header. | ||
98 | * | ||
99 | * NOTES: - it may return pointer pointing beyond end of packet, | ||
100 | * if the last recognized header is truncated in the middle. | ||
101 | * - if packet is truncated, so that all parsed headers are skipped, | ||
102 | * it returns -1. | ||
103 | * - if packet is fragmented, return pointer of the fragment header. | ||
104 | * - ESP is unparsable for now and considered like | ||
105 | * normal payload protocol. | ||
106 | * - Note also special handling of AUTH header. Thanks to IPsec wizards. | ||
107 | */ | ||
108 | |||
109 | int nf_ct_ipv6_skip_exthdr(struct sk_buff *skb, int start, u8 *nexthdrp, | ||
110 | int len) | ||
111 | { | ||
112 | u8 nexthdr = *nexthdrp; | ||
113 | |||
114 | while (ipv6_ext_hdr(nexthdr)) { | ||
115 | struct ipv6_opt_hdr hdr; | ||
116 | int hdrlen; | ||
117 | |||
118 | if (len < (int)sizeof(struct ipv6_opt_hdr)) | ||
119 | return -1; | ||
120 | if (nexthdr == NEXTHDR_NONE) | ||
121 | break; | ||
122 | if (nexthdr == NEXTHDR_FRAGMENT) | ||
123 | break; | ||
124 | if (skb_copy_bits(skb, start, &hdr, sizeof(hdr))) | ||
125 | BUG(); | ||
126 | if (nexthdr == NEXTHDR_AUTH) | ||
127 | hdrlen = (hdr.hdrlen+2)<<2; | ||
128 | else | ||
129 | hdrlen = ipv6_optlen(&hdr); | ||
130 | |||
131 | nexthdr = hdr.nexthdr; | ||
132 | len -= hdrlen; | ||
133 | start += hdrlen; | ||
134 | } | ||
135 | |||
136 | *nexthdrp = nexthdr; | ||
137 | return start; | ||
138 | } | ||
139 | |||
140 | static int | ||
141 | ipv6_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff, | ||
142 | u_int8_t *protonum) | ||
143 | { | ||
144 | unsigned int extoff; | ||
145 | unsigned char pnum; | ||
146 | int protoff; | ||
147 | |||
148 | extoff = (u8*)((*pskb)->nh.ipv6h + 1) - (*pskb)->data; | ||
149 | pnum = (*pskb)->nh.ipv6h->nexthdr; | ||
150 | |||
151 | protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum, | ||
152 | (*pskb)->len - extoff); | ||
153 | |||
154 | /* | ||
155 | * (protoff == (*pskb)->len) mean that the packet doesn't have no data | ||
156 | * except of IPv6 & ext headers. but it's tracked anyway. - YK | ||
157 | */ | ||
158 | if ((protoff < 0) || (protoff > (*pskb)->len)) { | ||
159 | DEBUGP("ip6_conntrack_core: can't find proto in pkt\n"); | ||
160 | NF_CT_STAT_INC(error); | ||
161 | NF_CT_STAT_INC(invalid); | ||
162 | return -NF_ACCEPT; | ||
163 | } | ||
164 | |||
165 | *dataoff = protoff; | ||
166 | *protonum = pnum; | ||
167 | return NF_ACCEPT; | ||
168 | } | ||
169 | |||
170 | static u_int32_t ipv6_get_features(const struct nf_conntrack_tuple *tuple) | ||
171 | { | ||
172 | return NF_CT_F_BASIC; | ||
173 | } | ||
174 | |||
175 | static unsigned int ipv6_confirm(unsigned int hooknum, | ||
176 | struct sk_buff **pskb, | ||
177 | const struct net_device *in, | ||
178 | const struct net_device *out, | ||
179 | int (*okfn)(struct sk_buff *)) | ||
180 | { | ||
181 | struct nf_conn *ct; | ||
182 | enum ip_conntrack_info ctinfo; | ||
183 | |||
184 | /* This is where we call the helper: as the packet goes out. */ | ||
185 | ct = nf_ct_get(*pskb, &ctinfo); | ||
186 | if (ct && ct->helper) { | ||
187 | unsigned int ret, protoff; | ||
188 | unsigned int extoff = (u8*)((*pskb)->nh.ipv6h + 1) | ||
189 | - (*pskb)->data; | ||
190 | unsigned char pnum = (*pskb)->nh.ipv6h->nexthdr; | ||
191 | |||
192 | protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum, | ||
193 | (*pskb)->len - extoff); | ||
194 | if (protoff < 0 || protoff > (*pskb)->len || | ||
195 | pnum == NEXTHDR_FRAGMENT) { | ||
196 | DEBUGP("proto header not found\n"); | ||
197 | return NF_ACCEPT; | ||
198 | } | ||
199 | |||
200 | ret = ct->helper->help(pskb, protoff, ct, ctinfo); | ||
201 | if (ret != NF_ACCEPT) | ||
202 | return ret; | ||
203 | } | ||
204 | |||
205 | /* We've seen it coming out the other side: confirm it */ | ||
206 | |||
207 | return nf_conntrack_confirm(pskb); | ||
208 | } | ||
209 | |||
210 | extern struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb); | ||
211 | extern void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb, | ||
212 | struct net_device *in, | ||
213 | struct net_device *out, | ||
214 | int (*okfn)(struct sk_buff *)); | ||
215 | static unsigned int ipv6_defrag(unsigned int hooknum, | ||
216 | struct sk_buff **pskb, | ||
217 | const struct net_device *in, | ||
218 | const struct net_device *out, | ||
219 | int (*okfn)(struct sk_buff *)) | ||
220 | { | ||
221 | struct sk_buff *reasm; | ||
222 | |||
223 | /* Previously seen (loopback)? */ | ||
224 | if ((*pskb)->nfct) | ||
225 | return NF_ACCEPT; | ||
226 | |||
227 | reasm = nf_ct_frag6_gather(*pskb); | ||
228 | |||
229 | /* queued */ | ||
230 | if (reasm == NULL) | ||
231 | return NF_STOLEN; | ||
232 | |||
233 | /* error occured or not fragmented */ | ||
234 | if (reasm == *pskb) | ||
235 | return NF_ACCEPT; | ||
236 | |||
237 | nf_ct_frag6_output(hooknum, reasm, (struct net_device *)in, | ||
238 | (struct net_device *)out, okfn); | ||
239 | |||
240 | return NF_STOLEN; | ||
241 | } | ||
242 | |||
243 | static unsigned int ipv6_conntrack_in(unsigned int hooknum, | ||
244 | struct sk_buff **pskb, | ||
245 | const struct net_device *in, | ||
246 | const struct net_device *out, | ||
247 | int (*okfn)(struct sk_buff *)) | ||
248 | { | ||
249 | struct sk_buff *reasm = (*pskb)->nfct_reasm; | ||
250 | |||
251 | /* This packet is fragmented and has reassembled packet. */ | ||
252 | if (reasm) { | ||
253 | /* Reassembled packet isn't parsed yet ? */ | ||
254 | if (!reasm->nfct) { | ||
255 | unsigned int ret; | ||
256 | |||
257 | ret = nf_conntrack_in(PF_INET6, hooknum, &reasm); | ||
258 | if (ret != NF_ACCEPT) | ||
259 | return ret; | ||
260 | } | ||
261 | nf_conntrack_get(reasm->nfct); | ||
262 | (*pskb)->nfct = reasm->nfct; | ||
263 | return NF_ACCEPT; | ||
264 | } | ||
265 | |||
266 | return nf_conntrack_in(PF_INET6, hooknum, pskb); | ||
267 | } | ||
268 | |||
269 | static unsigned int ipv6_conntrack_local(unsigned int hooknum, | ||
270 | struct sk_buff **pskb, | ||
271 | const struct net_device *in, | ||
272 | const struct net_device *out, | ||
273 | int (*okfn)(struct sk_buff *)) | ||
274 | { | ||
275 | /* root is playing with raw sockets. */ | ||
276 | if ((*pskb)->len < sizeof(struct ipv6hdr)) { | ||
277 | if (net_ratelimit()) | ||
278 | printk("ipv6_conntrack_local: packet too short\n"); | ||
279 | return NF_ACCEPT; | ||
280 | } | ||
281 | return ipv6_conntrack_in(hooknum, pskb, in, out, okfn); | ||
282 | } | ||
283 | |||
284 | /* Connection tracking may drop packets, but never alters them, so | ||
285 | make it the first hook. */ | ||
286 | static struct nf_hook_ops ipv6_conntrack_defrag_ops = { | ||
287 | .hook = ipv6_defrag, | ||
288 | .owner = THIS_MODULE, | ||
289 | .pf = PF_INET6, | ||
290 | .hooknum = NF_IP6_PRE_ROUTING, | ||
291 | .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, | ||
292 | }; | ||
293 | |||
294 | static struct nf_hook_ops ipv6_conntrack_in_ops = { | ||
295 | .hook = ipv6_conntrack_in, | ||
296 | .owner = THIS_MODULE, | ||
297 | .pf = PF_INET6, | ||
298 | .hooknum = NF_IP6_PRE_ROUTING, | ||
299 | .priority = NF_IP6_PRI_CONNTRACK, | ||
300 | }; | ||
301 | |||
302 | static struct nf_hook_ops ipv6_conntrack_local_out_ops = { | ||
303 | .hook = ipv6_conntrack_local, | ||
304 | .owner = THIS_MODULE, | ||
305 | .pf = PF_INET6, | ||
306 | .hooknum = NF_IP6_LOCAL_OUT, | ||
307 | .priority = NF_IP6_PRI_CONNTRACK, | ||
308 | }; | ||
309 | |||
310 | static struct nf_hook_ops ipv6_conntrack_defrag_local_out_ops = { | ||
311 | .hook = ipv6_defrag, | ||
312 | .owner = THIS_MODULE, | ||
313 | .pf = PF_INET6, | ||
314 | .hooknum = NF_IP6_LOCAL_OUT, | ||
315 | .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, | ||
316 | }; | ||
317 | |||
318 | /* Refragmenter; last chance. */ | ||
319 | static struct nf_hook_ops ipv6_conntrack_out_ops = { | ||
320 | .hook = ipv6_confirm, | ||
321 | .owner = THIS_MODULE, | ||
322 | .pf = PF_INET6, | ||
323 | .hooknum = NF_IP6_POST_ROUTING, | ||
324 | .priority = NF_IP6_PRI_LAST, | ||
325 | }; | ||
326 | |||
327 | static struct nf_hook_ops ipv6_conntrack_local_in_ops = { | ||
328 | .hook = ipv6_confirm, | ||
329 | .owner = THIS_MODULE, | ||
330 | .pf = PF_INET6, | ||
331 | .hooknum = NF_IP6_LOCAL_IN, | ||
332 | .priority = NF_IP6_PRI_LAST-1, | ||
333 | }; | ||
334 | |||
335 | #ifdef CONFIG_SYSCTL | ||
336 | |||
337 | /* From nf_conntrack_proto_icmpv6.c */ | ||
338 | extern unsigned long nf_ct_icmpv6_timeout; | ||
339 | |||
340 | /* From nf_conntrack_frag6.c */ | ||
341 | extern unsigned long nf_ct_frag6_timeout; | ||
342 | extern unsigned long nf_ct_frag6_low_thresh; | ||
343 | extern unsigned long nf_ct_frag6_high_thresh; | ||
344 | |||
345 | static struct ctl_table_header *nf_ct_ipv6_sysctl_header; | ||
346 | |||
347 | static ctl_table nf_ct_sysctl_table[] = { | ||
348 | { | ||
349 | .ctl_name = NET_NF_CONNTRACK_ICMPV6_TIMEOUT, | ||
350 | .procname = "nf_conntrack_icmpv6_timeout", | ||
351 | .data = &nf_ct_icmpv6_timeout, | ||
352 | .maxlen = sizeof(unsigned int), | ||
353 | .mode = 0644, | ||
354 | .proc_handler = &proc_dointvec_jiffies, | ||
355 | }, | ||
356 | { | ||
357 | .ctl_name = NET_NF_CONNTRACK_FRAG6_TIMEOUT, | ||
358 | .procname = "nf_conntrack_frag6_timeout", | ||
359 | .data = &nf_ct_frag6_timeout, | ||
360 | .maxlen = sizeof(unsigned int), | ||
361 | .mode = 0644, | ||
362 | .proc_handler = &proc_dointvec_jiffies, | ||
363 | }, | ||
364 | { | ||
365 | .ctl_name = NET_NF_CONNTRACK_FRAG6_LOW_THRESH, | ||
366 | .procname = "nf_conntrack_frag6_low_thresh", | ||
367 | .data = &nf_ct_frag6_low_thresh, | ||
368 | .maxlen = sizeof(unsigned int), | ||
369 | .mode = 0644, | ||
370 | .proc_handler = &proc_dointvec_jiffies, | ||
371 | }, | ||
372 | { | ||
373 | .ctl_name = NET_NF_CONNTRACK_FRAG6_HIGH_THRESH, | ||
374 | .procname = "nf_conntrack_frag6_high_thresh", | ||
375 | .data = &nf_ct_frag6_high_thresh, | ||
376 | .maxlen = sizeof(unsigned int), | ||
377 | .mode = 0644, | ||
378 | .proc_handler = &proc_dointvec_jiffies, | ||
379 | }, | ||
380 | { .ctl_name = 0 } | ||
381 | }; | ||
382 | |||
383 | static ctl_table nf_ct_netfilter_table[] = { | ||
384 | { | ||
385 | .ctl_name = NET_NETFILTER, | ||
386 | .procname = "netfilter", | ||
387 | .mode = 0555, | ||
388 | .child = nf_ct_sysctl_table, | ||
389 | }, | ||
390 | { .ctl_name = 0 } | ||
391 | }; | ||
392 | |||
393 | static ctl_table nf_ct_net_table[] = { | ||
394 | { | ||
395 | .ctl_name = CTL_NET, | ||
396 | .procname = "net", | ||
397 | .mode = 0555, | ||
398 | .child = nf_ct_netfilter_table, | ||
399 | }, | ||
400 | { .ctl_name = 0 } | ||
401 | }; | ||
402 | #endif | ||
403 | |||
404 | struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 = { | ||
405 | .l3proto = PF_INET6, | ||
406 | .name = "ipv6", | ||
407 | .pkt_to_tuple = ipv6_pkt_to_tuple, | ||
408 | .invert_tuple = ipv6_invert_tuple, | ||
409 | .print_tuple = ipv6_print_tuple, | ||
410 | .print_conntrack = ipv6_print_conntrack, | ||
411 | .prepare = ipv6_prepare, | ||
412 | .get_features = ipv6_get_features, | ||
413 | .me = THIS_MODULE, | ||
414 | }; | ||
415 | |||
416 | extern struct nf_conntrack_protocol nf_conntrack_protocol_tcp6; | ||
417 | extern struct nf_conntrack_protocol nf_conntrack_protocol_udp6; | ||
418 | extern struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6; | ||
419 | extern int nf_ct_frag6_init(void); | ||
420 | extern void nf_ct_frag6_cleanup(void); | ||
421 | static int init_or_cleanup(int init) | ||
422 | { | ||
423 | int ret = 0; | ||
424 | |||
425 | if (!init) goto cleanup; | ||
426 | |||
427 | ret = nf_ct_frag6_init(); | ||
428 | if (ret < 0) { | ||
429 | printk("nf_conntrack_ipv6: can't initialize frag6.\n"); | ||
430 | goto cleanup_nothing; | ||
431 | } | ||
432 | ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_tcp6); | ||
433 | if (ret < 0) { | ||
434 | printk("nf_conntrack_ipv6: can't register tcp.\n"); | ||
435 | goto cleanup_frag6; | ||
436 | } | ||
437 | |||
438 | ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_udp6); | ||
439 | if (ret < 0) { | ||
440 | printk("nf_conntrack_ipv6: can't register udp.\n"); | ||
441 | goto cleanup_tcp; | ||
442 | } | ||
443 | |||
444 | ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_icmpv6); | ||
445 | if (ret < 0) { | ||
446 | printk("nf_conntrack_ipv6: can't register icmpv6.\n"); | ||
447 | goto cleanup_udp; | ||
448 | } | ||
449 | |||
450 | ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv6); | ||
451 | if (ret < 0) { | ||
452 | printk("nf_conntrack_ipv6: can't register ipv6\n"); | ||
453 | goto cleanup_icmpv6; | ||
454 | } | ||
455 | |||
456 | ret = nf_register_hook(&ipv6_conntrack_defrag_ops); | ||
457 | if (ret < 0) { | ||
458 | printk("nf_conntrack_ipv6: can't register pre-routing defrag " | ||
459 | "hook.\n"); | ||
460 | goto cleanup_ipv6; | ||
461 | } | ||
462 | |||
463 | ret = nf_register_hook(&ipv6_conntrack_defrag_local_out_ops); | ||
464 | if (ret < 0) { | ||
465 | printk("nf_conntrack_ipv6: can't register local_out defrag " | ||
466 | "hook.\n"); | ||
467 | goto cleanup_defragops; | ||
468 | } | ||
469 | |||
470 | ret = nf_register_hook(&ipv6_conntrack_in_ops); | ||
471 | if (ret < 0) { | ||
472 | printk("nf_conntrack_ipv6: can't register pre-routing hook.\n"); | ||
473 | goto cleanup_defraglocalops; | ||
474 | } | ||
475 | |||
476 | ret = nf_register_hook(&ipv6_conntrack_local_out_ops); | ||
477 | if (ret < 0) { | ||
478 | printk("nf_conntrack_ipv6: can't register local out hook.\n"); | ||
479 | goto cleanup_inops; | ||
480 | } | ||
481 | |||
482 | ret = nf_register_hook(&ipv6_conntrack_out_ops); | ||
483 | if (ret < 0) { | ||
484 | printk("nf_conntrack_ipv6: can't register post-routing hook.\n"); | ||
485 | goto cleanup_inandlocalops; | ||
486 | } | ||
487 | |||
488 | ret = nf_register_hook(&ipv6_conntrack_local_in_ops); | ||
489 | if (ret < 0) { | ||
490 | printk("nf_conntrack_ipv6: can't register local in hook.\n"); | ||
491 | goto cleanup_inoutandlocalops; | ||
492 | } | ||
493 | |||
494 | #ifdef CONFIG_SYSCTL | ||
495 | nf_ct_ipv6_sysctl_header = register_sysctl_table(nf_ct_net_table, 0); | ||
496 | if (nf_ct_ipv6_sysctl_header == NULL) { | ||
497 | printk("nf_conntrack: can't register to sysctl.\n"); | ||
498 | ret = -ENOMEM; | ||
499 | goto cleanup_localinops; | ||
500 | } | ||
501 | #endif | ||
502 | return ret; | ||
503 | |||
504 | cleanup: | ||
505 | synchronize_net(); | ||
506 | #ifdef CONFIG_SYSCTL | ||
507 | unregister_sysctl_table(nf_ct_ipv6_sysctl_header); | ||
508 | cleanup_localinops: | ||
509 | #endif | ||
510 | nf_unregister_hook(&ipv6_conntrack_local_in_ops); | ||
511 | cleanup_inoutandlocalops: | ||
512 | nf_unregister_hook(&ipv6_conntrack_out_ops); | ||
513 | cleanup_inandlocalops: | ||
514 | nf_unregister_hook(&ipv6_conntrack_local_out_ops); | ||
515 | cleanup_inops: | ||
516 | nf_unregister_hook(&ipv6_conntrack_in_ops); | ||
517 | cleanup_defraglocalops: | ||
518 | nf_unregister_hook(&ipv6_conntrack_defrag_local_out_ops); | ||
519 | cleanup_defragops: | ||
520 | nf_unregister_hook(&ipv6_conntrack_defrag_ops); | ||
521 | cleanup_ipv6: | ||
522 | nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6); | ||
523 | cleanup_icmpv6: | ||
524 | nf_conntrack_protocol_unregister(&nf_conntrack_protocol_icmpv6); | ||
525 | cleanup_udp: | ||
526 | nf_conntrack_protocol_unregister(&nf_conntrack_protocol_udp6); | ||
527 | cleanup_tcp: | ||
528 | nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp6); | ||
529 | cleanup_frag6: | ||
530 | nf_ct_frag6_cleanup(); | ||
531 | cleanup_nothing: | ||
532 | return ret; | ||
533 | } | ||
534 | |||
535 | MODULE_LICENSE("GPL"); | ||
536 | MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>"); | ||
537 | |||
538 | static int __init init(void) | ||
539 | { | ||
540 | need_nf_conntrack(); | ||
541 | return init_or_cleanup(1); | ||
542 | } | ||
543 | |||
544 | static void __exit fini(void) | ||
545 | { | ||
546 | init_or_cleanup(0); | ||
547 | } | ||
548 | |||
549 | module_init(init); | ||
550 | module_exit(fini); | ||
551 | |||
552 | void need_ip6_conntrack(void) | ||
553 | { | ||
554 | } | ||
555 | |||
556 | EXPORT_SYMBOL(need_ip6_conntrack); | ||
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c new file mode 100644 index 000000000000..c0f1da5497a9 --- /dev/null +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | |||
@@ -0,0 +1,272 @@ | |||
1 | /* | ||
2 | * Copyright (C)2003,2004 USAGI/WIDE Project | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * Author: | ||
9 | * Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
10 | * | ||
11 | * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
12 | * - ICMPv6 tracking support. Derived from the original ip_conntrack code | ||
13 | * net/ipv4/netfilter/ip_conntrack_proto_icmp.c which had the following | ||
14 | * copyright information: | ||
15 | * (C) 1999-2001 Paul `Rusty' Russell | ||
16 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
17 | */ | ||
18 | |||
19 | #include <linux/types.h> | ||
20 | #include <linux/sched.h> | ||
21 | #include <linux/timer.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/netfilter.h> | ||
24 | #include <linux/in6.h> | ||
25 | #include <linux/icmpv6.h> | ||
26 | #include <linux/ipv6.h> | ||
27 | #include <net/ipv6.h> | ||
28 | #include <net/ip6_checksum.h> | ||
29 | #include <linux/seq_file.h> | ||
30 | #include <linux/netfilter_ipv6.h> | ||
31 | #include <net/netfilter/nf_conntrack_tuple.h> | ||
32 | #include <net/netfilter/nf_conntrack_protocol.h> | ||
33 | #include <net/netfilter/nf_conntrack_core.h> | ||
34 | #include <net/netfilter/ipv6/nf_conntrack_icmpv6.h> | ||
35 | |||
36 | unsigned long nf_ct_icmpv6_timeout = 30*HZ; | ||
37 | |||
38 | #if 0 | ||
39 | #define DEBUGP printk | ||
40 | #else | ||
41 | #define DEBUGP(format, args...) | ||
42 | #endif | ||
43 | |||
44 | static int icmpv6_pkt_to_tuple(const struct sk_buff *skb, | ||
45 | unsigned int dataoff, | ||
46 | struct nf_conntrack_tuple *tuple) | ||
47 | { | ||
48 | struct icmp6hdr _hdr, *hp; | ||
49 | |||
50 | hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); | ||
51 | if (hp == NULL) | ||
52 | return 0; | ||
53 | tuple->dst.u.icmp.type = hp->icmp6_type; | ||
54 | tuple->src.u.icmp.id = hp->icmp6_identifier; | ||
55 | tuple->dst.u.icmp.code = hp->icmp6_code; | ||
56 | |||
57 | return 1; | ||
58 | } | ||
59 | |||
60 | static int icmpv6_invert_tuple(struct nf_conntrack_tuple *tuple, | ||
61 | const struct nf_conntrack_tuple *orig) | ||
62 | { | ||
63 | /* Add 1; spaces filled with 0. */ | ||
64 | static u_int8_t invmap[] = { | ||
65 | [ICMPV6_ECHO_REQUEST - 128] = ICMPV6_ECHO_REPLY + 1, | ||
66 | [ICMPV6_ECHO_REPLY - 128] = ICMPV6_ECHO_REQUEST + 1, | ||
67 | [ICMPV6_NI_QUERY - 128] = ICMPV6_NI_QUERY + 1, | ||
68 | [ICMPV6_NI_REPLY - 128] = ICMPV6_NI_REPLY +1 | ||
69 | }; | ||
70 | |||
71 | __u8 type = orig->dst.u.icmp.type - 128; | ||
72 | if (type >= sizeof(invmap) || !invmap[type]) | ||
73 | return 0; | ||
74 | |||
75 | tuple->src.u.icmp.id = orig->src.u.icmp.id; | ||
76 | tuple->dst.u.icmp.type = invmap[type] - 1; | ||
77 | tuple->dst.u.icmp.code = orig->dst.u.icmp.code; | ||
78 | return 1; | ||
79 | } | ||
80 | |||
81 | /* Print out the per-protocol part of the tuple. */ | ||
82 | static int icmpv6_print_tuple(struct seq_file *s, | ||
83 | const struct nf_conntrack_tuple *tuple) | ||
84 | { | ||
85 | return seq_printf(s, "type=%u code=%u id=%u ", | ||
86 | tuple->dst.u.icmp.type, | ||
87 | tuple->dst.u.icmp.code, | ||
88 | ntohs(tuple->src.u.icmp.id)); | ||
89 | } | ||
90 | |||
91 | /* Print out the private part of the conntrack. */ | ||
92 | static int icmpv6_print_conntrack(struct seq_file *s, | ||
93 | const struct nf_conn *conntrack) | ||
94 | { | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | /* Returns verdict for packet, or -1 for invalid. */ | ||
99 | static int icmpv6_packet(struct nf_conn *ct, | ||
100 | const struct sk_buff *skb, | ||
101 | unsigned int dataoff, | ||
102 | enum ip_conntrack_info ctinfo, | ||
103 | int pf, | ||
104 | unsigned int hooknum) | ||
105 | { | ||
106 | /* Try to delete connection immediately after all replies: | ||
107 | won't actually vanish as we still have skb, and del_timer | ||
108 | means this will only run once even if count hits zero twice | ||
109 | (theoretically possible with SMP) */ | ||
110 | if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) { | ||
111 | if (atomic_dec_and_test(&ct->proto.icmp.count) | ||
112 | && del_timer(&ct->timeout)) | ||
113 | ct->timeout.function((unsigned long)ct); | ||
114 | } else { | ||
115 | atomic_inc(&ct->proto.icmp.count); | ||
116 | nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb); | ||
117 | nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmpv6_timeout); | ||
118 | } | ||
119 | |||
120 | return NF_ACCEPT; | ||
121 | } | ||
122 | |||
123 | /* Called when a new connection for this protocol found. */ | ||
124 | static int icmpv6_new(struct nf_conn *conntrack, | ||
125 | const struct sk_buff *skb, | ||
126 | unsigned int dataoff) | ||
127 | { | ||
128 | static u_int8_t valid_new[] = { | ||
129 | [ICMPV6_ECHO_REQUEST - 128] = 1, | ||
130 | [ICMPV6_NI_QUERY - 128] = 1 | ||
131 | }; | ||
132 | |||
133 | if (conntrack->tuplehash[0].tuple.dst.u.icmp.type - 128 >= sizeof(valid_new) | ||
134 | || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type - 128]) { | ||
135 | /* Can't create a new ICMPv6 `conn' with this. */ | ||
136 | DEBUGP("icmp: can't create new conn with type %u\n", | ||
137 | conntrack->tuplehash[0].tuple.dst.u.icmp.type); | ||
138 | NF_CT_DUMP_TUPLE(&conntrack->tuplehash[0].tuple); | ||
139 | return 0; | ||
140 | } | ||
141 | atomic_set(&conntrack->proto.icmp.count, 0); | ||
142 | return 1; | ||
143 | } | ||
144 | |||
145 | extern int | ||
146 | nf_ct_ipv6_skip_exthdr(struct sk_buff *skb, int start, u8 *nexthdrp, int len); | ||
147 | extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6; | ||
148 | static int | ||
149 | icmpv6_error_message(struct sk_buff *skb, | ||
150 | unsigned int icmp6off, | ||
151 | enum ip_conntrack_info *ctinfo, | ||
152 | unsigned int hooknum) | ||
153 | { | ||
154 | struct nf_conntrack_tuple intuple, origtuple; | ||
155 | struct nf_conntrack_tuple_hash *h; | ||
156 | struct icmp6hdr _hdr, *hp; | ||
157 | unsigned int inip6off; | ||
158 | struct nf_conntrack_protocol *inproto; | ||
159 | u_int8_t inprotonum; | ||
160 | unsigned int inprotoff; | ||
161 | |||
162 | NF_CT_ASSERT(skb->nfct == NULL); | ||
163 | |||
164 | hp = skb_header_pointer(skb, icmp6off, sizeof(_hdr), &_hdr); | ||
165 | if (hp == NULL) { | ||
166 | DEBUGP("icmpv6_error: Can't get ICMPv6 hdr.\n"); | ||
167 | return -NF_ACCEPT; | ||
168 | } | ||
169 | |||
170 | inip6off = icmp6off + sizeof(_hdr); | ||
171 | if (skb_copy_bits(skb, inip6off+offsetof(struct ipv6hdr, nexthdr), | ||
172 | &inprotonum, sizeof(inprotonum)) != 0) { | ||
173 | DEBUGP("icmpv6_error: Can't get nexthdr in inner IPv6 header.\n"); | ||
174 | return -NF_ACCEPT; | ||
175 | } | ||
176 | inprotoff = nf_ct_ipv6_skip_exthdr(skb, | ||
177 | inip6off + sizeof(struct ipv6hdr), | ||
178 | &inprotonum, | ||
179 | skb->len - inip6off | ||
180 | - sizeof(struct ipv6hdr)); | ||
181 | |||
182 | if ((inprotoff < 0) || (inprotoff > skb->len) || | ||
183 | (inprotonum == NEXTHDR_FRAGMENT)) { | ||
184 | DEBUGP("icmpv6_error: Can't get protocol header in ICMPv6 payload.\n"); | ||
185 | return -NF_ACCEPT; | ||
186 | } | ||
187 | |||
188 | inproto = nf_ct_find_proto(PF_INET6, inprotonum); | ||
189 | |||
190 | /* Are they talking about one of our connections? */ | ||
191 | if (!nf_ct_get_tuple(skb, inip6off, inprotoff, PF_INET6, inprotonum, | ||
192 | &origtuple, &nf_conntrack_l3proto_ipv6, inproto)) { | ||
193 | DEBUGP("icmpv6_error: Can't get tuple\n"); | ||
194 | return -NF_ACCEPT; | ||
195 | } | ||
196 | |||
197 | /* Ordinarily, we'd expect the inverted tupleproto, but it's | ||
198 | been preserved inside the ICMP. */ | ||
199 | if (!nf_ct_invert_tuple(&intuple, &origtuple, | ||
200 | &nf_conntrack_l3proto_ipv6, inproto)) { | ||
201 | DEBUGP("icmpv6_error: Can't invert tuple\n"); | ||
202 | return -NF_ACCEPT; | ||
203 | } | ||
204 | |||
205 | *ctinfo = IP_CT_RELATED; | ||
206 | |||
207 | h = nf_conntrack_find_get(&intuple, NULL); | ||
208 | if (!h) { | ||
209 | DEBUGP("icmpv6_error: no match\n"); | ||
210 | return -NF_ACCEPT; | ||
211 | } else { | ||
212 | if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) | ||
213 | *ctinfo += IP_CT_IS_REPLY; | ||
214 | } | ||
215 | |||
216 | /* Update skb to refer to this connection */ | ||
217 | skb->nfct = &nf_ct_tuplehash_to_ctrack(h)->ct_general; | ||
218 | skb->nfctinfo = *ctinfo; | ||
219 | return -NF_ACCEPT; | ||
220 | } | ||
221 | |||
222 | static int | ||
223 | icmpv6_error(struct sk_buff *skb, unsigned int dataoff, | ||
224 | enum ip_conntrack_info *ctinfo, int pf, unsigned int hooknum) | ||
225 | { | ||
226 | struct icmp6hdr _ih, *icmp6h; | ||
227 | |||
228 | icmp6h = skb_header_pointer(skb, dataoff, sizeof(_ih), &_ih); | ||
229 | if (icmp6h == NULL) { | ||
230 | if (LOG_INVALID(IPPROTO_ICMPV6)) | ||
231 | nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL, | ||
232 | "nf_ct_icmpv6: short packet "); | ||
233 | return -NF_ACCEPT; | ||
234 | } | ||
235 | |||
236 | if (hooknum != NF_IP6_PRE_ROUTING) | ||
237 | goto skipped; | ||
238 | |||
239 | /* Ignore it if the checksum's bogus. */ | ||
240 | if (csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr, | ||
241 | skb->len - dataoff, IPPROTO_ICMPV6, | ||
242 | skb_checksum(skb, dataoff, | ||
243 | skb->len - dataoff, 0))) { | ||
244 | nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL, | ||
245 | "nf_ct_icmpv6: ICMPv6 checksum failed\n"); | ||
246 | return -NF_ACCEPT; | ||
247 | } | ||
248 | |||
249 | skipped: | ||
250 | |||
251 | /* is not error message ? */ | ||
252 | if (icmp6h->icmp6_type >= 128) | ||
253 | return NF_ACCEPT; | ||
254 | |||
255 | return icmpv6_error_message(skb, dataoff, ctinfo, hooknum); | ||
256 | } | ||
257 | |||
258 | struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6 = | ||
259 | { | ||
260 | .l3proto = PF_INET6, | ||
261 | .proto = IPPROTO_ICMPV6, | ||
262 | .name = "icmpv6", | ||
263 | .pkt_to_tuple = icmpv6_pkt_to_tuple, | ||
264 | .invert_tuple = icmpv6_invert_tuple, | ||
265 | .print_tuple = icmpv6_print_tuple, | ||
266 | .print_conntrack = icmpv6_print_conntrack, | ||
267 | .packet = icmpv6_packet, | ||
268 | .new = icmpv6_new, | ||
269 | .error = icmpv6_error, | ||
270 | }; | ||
271 | |||
272 | EXPORT_SYMBOL(nf_conntrack_protocol_icmpv6); | ||
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c new file mode 100644 index 000000000000..7640b9bb7694 --- /dev/null +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
@@ -0,0 +1,885 @@ | |||
1 | /* | ||
2 | * IPv6 fragment reassembly for connection tracking | ||
3 | * | ||
4 | * Copyright (C)2004 USAGI/WIDE Project | ||
5 | * | ||
6 | * Author: | ||
7 | * Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
8 | * | ||
9 | * Based on: net/ipv6/reassembly.c | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version | ||
14 | * 2 of the License, or (at your option) any later version. | ||
15 | */ | ||
16 | |||
17 | #include <linux/config.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/socket.h> | ||
22 | #include <linux/sockios.h> | ||
23 | #include <linux/jiffies.h> | ||
24 | #include <linux/net.h> | ||
25 | #include <linux/list.h> | ||
26 | #include <linux/netdevice.h> | ||
27 | #include <linux/in6.h> | ||
28 | #include <linux/ipv6.h> | ||
29 | #include <linux/icmpv6.h> | ||
30 | #include <linux/random.h> | ||
31 | #include <linux/jhash.h> | ||
32 | |||
33 | #include <net/sock.h> | ||
34 | #include <net/snmp.h> | ||
35 | |||
36 | #include <net/ipv6.h> | ||
37 | #include <net/protocol.h> | ||
38 | #include <net/transp_v6.h> | ||
39 | #include <net/rawv6.h> | ||
40 | #include <net/ndisc.h> | ||
41 | #include <net/addrconf.h> | ||
42 | #include <linux/sysctl.h> | ||
43 | #include <linux/netfilter.h> | ||
44 | #include <linux/netfilter_ipv6.h> | ||
45 | #include <linux/kernel.h> | ||
46 | #include <linux/module.h> | ||
47 | |||
48 | #if 0 | ||
49 | #define DEBUGP printk | ||
50 | #else | ||
51 | #define DEBUGP(format, args...) | ||
52 | #endif | ||
53 | |||
54 | #define NF_CT_FRAG6_HIGH_THRESH 262144 /* == 256*1024 */ | ||
55 | #define NF_CT_FRAG6_LOW_THRESH 196608 /* == 192*1024 */ | ||
56 | #define NF_CT_FRAG6_TIMEOUT IPV6_FRAG_TIMEOUT | ||
57 | |||
58 | int nf_ct_frag6_high_thresh = 256*1024; | ||
59 | int nf_ct_frag6_low_thresh = 192*1024; | ||
60 | int nf_ct_frag6_timeout = IPV6_FRAG_TIMEOUT; | ||
61 | |||
62 | struct nf_ct_frag6_skb_cb | ||
63 | { | ||
64 | struct inet6_skb_parm h; | ||
65 | int offset; | ||
66 | struct sk_buff *orig; | ||
67 | }; | ||
68 | |||
69 | #define NFCT_FRAG6_CB(skb) ((struct nf_ct_frag6_skb_cb*)((skb)->cb)) | ||
70 | |||
71 | struct nf_ct_frag6_queue | ||
72 | { | ||
73 | struct nf_ct_frag6_queue *next; | ||
74 | struct list_head lru_list; /* lru list member */ | ||
75 | |||
76 | __u32 id; /* fragment id */ | ||
77 | struct in6_addr saddr; | ||
78 | struct in6_addr daddr; | ||
79 | |||
80 | spinlock_t lock; | ||
81 | atomic_t refcnt; | ||
82 | struct timer_list timer; /* expire timer */ | ||
83 | struct sk_buff *fragments; | ||
84 | int len; | ||
85 | int meat; | ||
86 | struct timeval stamp; | ||
87 | unsigned int csum; | ||
88 | __u8 last_in; /* has first/last segment arrived? */ | ||
89 | #define COMPLETE 4 | ||
90 | #define FIRST_IN 2 | ||
91 | #define LAST_IN 1 | ||
92 | __u16 nhoffset; | ||
93 | struct nf_ct_frag6_queue **pprev; | ||
94 | }; | ||
95 | |||
96 | /* Hash table. */ | ||
97 | |||
98 | #define FRAG6Q_HASHSZ 64 | ||
99 | |||
100 | static struct nf_ct_frag6_queue *nf_ct_frag6_hash[FRAG6Q_HASHSZ]; | ||
101 | static rwlock_t nf_ct_frag6_lock = RW_LOCK_UNLOCKED; | ||
102 | static u32 nf_ct_frag6_hash_rnd; | ||
103 | static LIST_HEAD(nf_ct_frag6_lru_list); | ||
104 | int nf_ct_frag6_nqueues = 0; | ||
105 | |||
106 | static __inline__ void __fq_unlink(struct nf_ct_frag6_queue *fq) | ||
107 | { | ||
108 | if (fq->next) | ||
109 | fq->next->pprev = fq->pprev; | ||
110 | *fq->pprev = fq->next; | ||
111 | list_del(&fq->lru_list); | ||
112 | nf_ct_frag6_nqueues--; | ||
113 | } | ||
114 | |||
115 | static __inline__ void fq_unlink(struct nf_ct_frag6_queue *fq) | ||
116 | { | ||
117 | write_lock(&nf_ct_frag6_lock); | ||
118 | __fq_unlink(fq); | ||
119 | write_unlock(&nf_ct_frag6_lock); | ||
120 | } | ||
121 | |||
122 | static unsigned int ip6qhashfn(u32 id, struct in6_addr *saddr, | ||
123 | struct in6_addr *daddr) | ||
124 | { | ||
125 | u32 a, b, c; | ||
126 | |||
127 | a = saddr->s6_addr32[0]; | ||
128 | b = saddr->s6_addr32[1]; | ||
129 | c = saddr->s6_addr32[2]; | ||
130 | |||
131 | a += JHASH_GOLDEN_RATIO; | ||
132 | b += JHASH_GOLDEN_RATIO; | ||
133 | c += nf_ct_frag6_hash_rnd; | ||
134 | __jhash_mix(a, b, c); | ||
135 | |||
136 | a += saddr->s6_addr32[3]; | ||
137 | b += daddr->s6_addr32[0]; | ||
138 | c += daddr->s6_addr32[1]; | ||
139 | __jhash_mix(a, b, c); | ||
140 | |||
141 | a += daddr->s6_addr32[2]; | ||
142 | b += daddr->s6_addr32[3]; | ||
143 | c += id; | ||
144 | __jhash_mix(a, b, c); | ||
145 | |||
146 | return c & (FRAG6Q_HASHSZ - 1); | ||
147 | } | ||
148 | |||
149 | static struct timer_list nf_ct_frag6_secret_timer; | ||
150 | int nf_ct_frag6_secret_interval = 10 * 60 * HZ; | ||
151 | |||
152 | static void nf_ct_frag6_secret_rebuild(unsigned long dummy) | ||
153 | { | ||
154 | unsigned long now = jiffies; | ||
155 | int i; | ||
156 | |||
157 | write_lock(&nf_ct_frag6_lock); | ||
158 | get_random_bytes(&nf_ct_frag6_hash_rnd, sizeof(u32)); | ||
159 | for (i = 0; i < FRAG6Q_HASHSZ; i++) { | ||
160 | struct nf_ct_frag6_queue *q; | ||
161 | |||
162 | q = nf_ct_frag6_hash[i]; | ||
163 | while (q) { | ||
164 | struct nf_ct_frag6_queue *next = q->next; | ||
165 | unsigned int hval = ip6qhashfn(q->id, | ||
166 | &q->saddr, | ||
167 | &q->daddr); | ||
168 | |||
169 | if (hval != i) { | ||
170 | /* Unlink. */ | ||
171 | if (q->next) | ||
172 | q->next->pprev = q->pprev; | ||
173 | *q->pprev = q->next; | ||
174 | |||
175 | /* Relink to new hash chain. */ | ||
176 | if ((q->next = nf_ct_frag6_hash[hval]) != NULL) | ||
177 | q->next->pprev = &q->next; | ||
178 | nf_ct_frag6_hash[hval] = q; | ||
179 | q->pprev = &nf_ct_frag6_hash[hval]; | ||
180 | } | ||
181 | |||
182 | q = next; | ||
183 | } | ||
184 | } | ||
185 | write_unlock(&nf_ct_frag6_lock); | ||
186 | |||
187 | mod_timer(&nf_ct_frag6_secret_timer, now + nf_ct_frag6_secret_interval); | ||
188 | } | ||
189 | |||
190 | atomic_t nf_ct_frag6_mem = ATOMIC_INIT(0); | ||
191 | |||
192 | /* Memory Tracking Functions. */ | ||
193 | static inline void frag_kfree_skb(struct sk_buff *skb) | ||
194 | { | ||
195 | atomic_sub(skb->truesize, &nf_ct_frag6_mem); | ||
196 | if (NFCT_FRAG6_CB(skb)->orig) | ||
197 | kfree_skb(NFCT_FRAG6_CB(skb)->orig); | ||
198 | |||
199 | kfree_skb(skb); | ||
200 | } | ||
201 | |||
202 | static inline void frag_free_queue(struct nf_ct_frag6_queue *fq) | ||
203 | { | ||
204 | atomic_sub(sizeof(struct nf_ct_frag6_queue), &nf_ct_frag6_mem); | ||
205 | kfree(fq); | ||
206 | } | ||
207 | |||
208 | static inline struct nf_ct_frag6_queue *frag_alloc_queue(void) | ||
209 | { | ||
210 | struct nf_ct_frag6_queue *fq = kmalloc(sizeof(struct nf_ct_frag6_queue), GFP_ATOMIC); | ||
211 | |||
212 | if (!fq) | ||
213 | return NULL; | ||
214 | atomic_add(sizeof(struct nf_ct_frag6_queue), &nf_ct_frag6_mem); | ||
215 | return fq; | ||
216 | } | ||
217 | |||
218 | /* Destruction primitives. */ | ||
219 | |||
220 | /* Complete destruction of fq. */ | ||
221 | static void nf_ct_frag6_destroy(struct nf_ct_frag6_queue *fq) | ||
222 | { | ||
223 | struct sk_buff *fp; | ||
224 | |||
225 | BUG_TRAP(fq->last_in&COMPLETE); | ||
226 | BUG_TRAP(del_timer(&fq->timer) == 0); | ||
227 | |||
228 | /* Release all fragment data. */ | ||
229 | fp = fq->fragments; | ||
230 | while (fp) { | ||
231 | struct sk_buff *xp = fp->next; | ||
232 | |||
233 | frag_kfree_skb(fp); | ||
234 | fp = xp; | ||
235 | } | ||
236 | |||
237 | frag_free_queue(fq); | ||
238 | } | ||
239 | |||
240 | static __inline__ void fq_put(struct nf_ct_frag6_queue *fq) | ||
241 | { | ||
242 | if (atomic_dec_and_test(&fq->refcnt)) | ||
243 | nf_ct_frag6_destroy(fq); | ||
244 | } | ||
245 | |||
246 | /* Kill fq entry. It is not destroyed immediately, | ||
247 | * because caller (and someone more) holds reference count. | ||
248 | */ | ||
249 | static __inline__ void fq_kill(struct nf_ct_frag6_queue *fq) | ||
250 | { | ||
251 | if (del_timer(&fq->timer)) | ||
252 | atomic_dec(&fq->refcnt); | ||
253 | |||
254 | if (!(fq->last_in & COMPLETE)) { | ||
255 | fq_unlink(fq); | ||
256 | atomic_dec(&fq->refcnt); | ||
257 | fq->last_in |= COMPLETE; | ||
258 | } | ||
259 | } | ||
260 | |||
261 | static void nf_ct_frag6_evictor(void) | ||
262 | { | ||
263 | struct nf_ct_frag6_queue *fq; | ||
264 | struct list_head *tmp; | ||
265 | |||
266 | for (;;) { | ||
267 | if (atomic_read(&nf_ct_frag6_mem) <= nf_ct_frag6_low_thresh) | ||
268 | return; | ||
269 | read_lock(&nf_ct_frag6_lock); | ||
270 | if (list_empty(&nf_ct_frag6_lru_list)) { | ||
271 | read_unlock(&nf_ct_frag6_lock); | ||
272 | return; | ||
273 | } | ||
274 | tmp = nf_ct_frag6_lru_list.next; | ||
275 | fq = list_entry(tmp, struct nf_ct_frag6_queue, lru_list); | ||
276 | atomic_inc(&fq->refcnt); | ||
277 | read_unlock(&nf_ct_frag6_lock); | ||
278 | |||
279 | spin_lock(&fq->lock); | ||
280 | if (!(fq->last_in&COMPLETE)) | ||
281 | fq_kill(fq); | ||
282 | spin_unlock(&fq->lock); | ||
283 | |||
284 | fq_put(fq); | ||
285 | } | ||
286 | } | ||
287 | |||
288 | static void nf_ct_frag6_expire(unsigned long data) | ||
289 | { | ||
290 | struct nf_ct_frag6_queue *fq = (struct nf_ct_frag6_queue *) data; | ||
291 | |||
292 | spin_lock(&fq->lock); | ||
293 | |||
294 | if (fq->last_in & COMPLETE) | ||
295 | goto out; | ||
296 | |||
297 | fq_kill(fq); | ||
298 | |||
299 | out: | ||
300 | spin_unlock(&fq->lock); | ||
301 | fq_put(fq); | ||
302 | } | ||
303 | |||
304 | /* Creation primitives. */ | ||
305 | |||
306 | |||
307 | static struct nf_ct_frag6_queue *nf_ct_frag6_intern(unsigned int hash, | ||
308 | struct nf_ct_frag6_queue *fq_in) | ||
309 | { | ||
310 | struct nf_ct_frag6_queue *fq; | ||
311 | |||
312 | write_lock(&nf_ct_frag6_lock); | ||
313 | #ifdef CONFIG_SMP | ||
314 | for (fq = nf_ct_frag6_hash[hash]; fq; fq = fq->next) { | ||
315 | if (fq->id == fq_in->id && | ||
316 | !ipv6_addr_cmp(&fq_in->saddr, &fq->saddr) && | ||
317 | !ipv6_addr_cmp(&fq_in->daddr, &fq->daddr)) { | ||
318 | atomic_inc(&fq->refcnt); | ||
319 | write_unlock(&nf_ct_frag6_lock); | ||
320 | fq_in->last_in |= COMPLETE; | ||
321 | fq_put(fq_in); | ||
322 | return fq; | ||
323 | } | ||
324 | } | ||
325 | #endif | ||
326 | fq = fq_in; | ||
327 | |||
328 | if (!mod_timer(&fq->timer, jiffies + nf_ct_frag6_timeout)) | ||
329 | atomic_inc(&fq->refcnt); | ||
330 | |||
331 | atomic_inc(&fq->refcnt); | ||
332 | if ((fq->next = nf_ct_frag6_hash[hash]) != NULL) | ||
333 | fq->next->pprev = &fq->next; | ||
334 | nf_ct_frag6_hash[hash] = fq; | ||
335 | fq->pprev = &nf_ct_frag6_hash[hash]; | ||
336 | INIT_LIST_HEAD(&fq->lru_list); | ||
337 | list_add_tail(&fq->lru_list, &nf_ct_frag6_lru_list); | ||
338 | nf_ct_frag6_nqueues++; | ||
339 | write_unlock(&nf_ct_frag6_lock); | ||
340 | return fq; | ||
341 | } | ||
342 | |||
343 | |||
344 | static struct nf_ct_frag6_queue * | ||
345 | nf_ct_frag6_create(unsigned int hash, u32 id, struct in6_addr *src, struct in6_addr *dst) | ||
346 | { | ||
347 | struct nf_ct_frag6_queue *fq; | ||
348 | |||
349 | if ((fq = frag_alloc_queue()) == NULL) { | ||
350 | DEBUGP("Can't alloc new queue\n"); | ||
351 | goto oom; | ||
352 | } | ||
353 | |||
354 | memset(fq, 0, sizeof(struct nf_ct_frag6_queue)); | ||
355 | |||
356 | fq->id = id; | ||
357 | ipv6_addr_copy(&fq->saddr, src); | ||
358 | ipv6_addr_copy(&fq->daddr, dst); | ||
359 | |||
360 | init_timer(&fq->timer); | ||
361 | fq->timer.function = nf_ct_frag6_expire; | ||
362 | fq->timer.data = (long) fq; | ||
363 | fq->lock = SPIN_LOCK_UNLOCKED; | ||
364 | atomic_set(&fq->refcnt, 1); | ||
365 | |||
366 | return nf_ct_frag6_intern(hash, fq); | ||
367 | |||
368 | oom: | ||
369 | return NULL; | ||
370 | } | ||
371 | |||
372 | static __inline__ struct nf_ct_frag6_queue * | ||
373 | fq_find(u32 id, struct in6_addr *src, struct in6_addr *dst) | ||
374 | { | ||
375 | struct nf_ct_frag6_queue *fq; | ||
376 | unsigned int hash = ip6qhashfn(id, src, dst); | ||
377 | |||
378 | read_lock(&nf_ct_frag6_lock); | ||
379 | for (fq = nf_ct_frag6_hash[hash]; fq; fq = fq->next) { | ||
380 | if (fq->id == id && | ||
381 | !ipv6_addr_cmp(src, &fq->saddr) && | ||
382 | !ipv6_addr_cmp(dst, &fq->daddr)) { | ||
383 | atomic_inc(&fq->refcnt); | ||
384 | read_unlock(&nf_ct_frag6_lock); | ||
385 | return fq; | ||
386 | } | ||
387 | } | ||
388 | read_unlock(&nf_ct_frag6_lock); | ||
389 | |||
390 | return nf_ct_frag6_create(hash, id, src, dst); | ||
391 | } | ||
392 | |||
393 | |||
394 | static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, | ||
395 | struct frag_hdr *fhdr, int nhoff) | ||
396 | { | ||
397 | struct sk_buff *prev, *next; | ||
398 | int offset, end; | ||
399 | |||
400 | if (fq->last_in & COMPLETE) { | ||
401 | DEBUGP("Allready completed\n"); | ||
402 | goto err; | ||
403 | } | ||
404 | |||
405 | offset = ntohs(fhdr->frag_off) & ~0x7; | ||
406 | end = offset + (ntohs(skb->nh.ipv6h->payload_len) - | ||
407 | ((u8 *) (fhdr + 1) - (u8 *) (skb->nh.ipv6h + 1))); | ||
408 | |||
409 | if ((unsigned int)end > IPV6_MAXPLEN) { | ||
410 | DEBUGP("offset is too large.\n"); | ||
411 | return -1; | ||
412 | } | ||
413 | |||
414 | if (skb->ip_summed == CHECKSUM_HW) | ||
415 | skb->csum = csum_sub(skb->csum, | ||
416 | csum_partial(skb->nh.raw, | ||
417 | (u8*)(fhdr + 1) - skb->nh.raw, | ||
418 | 0)); | ||
419 | |||
420 | /* Is this the final fragment? */ | ||
421 | if (!(fhdr->frag_off & htons(IP6_MF))) { | ||
422 | /* If we already have some bits beyond end | ||
423 | * or have different end, the segment is corrupted. | ||
424 | */ | ||
425 | if (end < fq->len || | ||
426 | ((fq->last_in & LAST_IN) && end != fq->len)) { | ||
427 | DEBUGP("already received last fragment\n"); | ||
428 | goto err; | ||
429 | } | ||
430 | fq->last_in |= LAST_IN; | ||
431 | fq->len = end; | ||
432 | } else { | ||
433 | /* Check if the fragment is rounded to 8 bytes. | ||
434 | * Required by the RFC. | ||
435 | */ | ||
436 | if (end & 0x7) { | ||
437 | /* RFC2460 says always send parameter problem in | ||
438 | * this case. -DaveM | ||
439 | */ | ||
440 | DEBUGP("the end of this fragment is not rounded to 8 bytes.\n"); | ||
441 | return -1; | ||
442 | } | ||
443 | if (end > fq->len) { | ||
444 | /* Some bits beyond end -> corruption. */ | ||
445 | if (fq->last_in & LAST_IN) { | ||
446 | DEBUGP("last packet already reached.\n"); | ||
447 | goto err; | ||
448 | } | ||
449 | fq->len = end; | ||
450 | } | ||
451 | } | ||
452 | |||
453 | if (end == offset) | ||
454 | goto err; | ||
455 | |||
456 | /* Point into the IP datagram 'data' part. */ | ||
457 | if (!pskb_pull(skb, (u8 *) (fhdr + 1) - skb->data)) { | ||
458 | DEBUGP("queue: message is too short.\n"); | ||
459 | goto err; | ||
460 | } | ||
461 | if (end-offset < skb->len) { | ||
462 | if (pskb_trim(skb, end - offset)) { | ||
463 | DEBUGP("Can't trim\n"); | ||
464 | goto err; | ||
465 | } | ||
466 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) | ||
467 | skb->ip_summed = CHECKSUM_NONE; | ||
468 | } | ||
469 | |||
470 | /* Find out which fragments are in front and at the back of us | ||
471 | * in the chain of fragments so far. We must know where to put | ||
472 | * this fragment, right? | ||
473 | */ | ||
474 | prev = NULL; | ||
475 | for (next = fq->fragments; next != NULL; next = next->next) { | ||
476 | if (NFCT_FRAG6_CB(next)->offset >= offset) | ||
477 | break; /* bingo! */ | ||
478 | prev = next; | ||
479 | } | ||
480 | |||
481 | /* We found where to put this one. Check for overlap with | ||
482 | * preceding fragment, and, if needed, align things so that | ||
483 | * any overlaps are eliminated. | ||
484 | */ | ||
485 | if (prev) { | ||
486 | int i = (NFCT_FRAG6_CB(prev)->offset + prev->len) - offset; | ||
487 | |||
488 | if (i > 0) { | ||
489 | offset += i; | ||
490 | if (end <= offset) { | ||
491 | DEBUGP("overlap\n"); | ||
492 | goto err; | ||
493 | } | ||
494 | if (!pskb_pull(skb, i)) { | ||
495 | DEBUGP("Can't pull\n"); | ||
496 | goto err; | ||
497 | } | ||
498 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) | ||
499 | skb->ip_summed = CHECKSUM_NONE; | ||
500 | } | ||
501 | } | ||
502 | |||
503 | /* Look for overlap with succeeding segments. | ||
504 | * If we can merge fragments, do it. | ||
505 | */ | ||
506 | while (next && NFCT_FRAG6_CB(next)->offset < end) { | ||
507 | /* overlap is 'i' bytes */ | ||
508 | int i = end - NFCT_FRAG6_CB(next)->offset; | ||
509 | |||
510 | if (i < next->len) { | ||
511 | /* Eat head of the next overlapped fragment | ||
512 | * and leave the loop. The next ones cannot overlap. | ||
513 | */ | ||
514 | DEBUGP("Eat head of the overlapped parts.: %d", i); | ||
515 | if (!pskb_pull(next, i)) | ||
516 | goto err; | ||
517 | |||
518 | /* next fragment */ | ||
519 | NFCT_FRAG6_CB(next)->offset += i; | ||
520 | fq->meat -= i; | ||
521 | if (next->ip_summed != CHECKSUM_UNNECESSARY) | ||
522 | next->ip_summed = CHECKSUM_NONE; | ||
523 | break; | ||
524 | } else { | ||
525 | struct sk_buff *free_it = next; | ||
526 | |||
527 | /* Old fragmnet is completely overridden with | ||
528 | * new one drop it. | ||
529 | */ | ||
530 | next = next->next; | ||
531 | |||
532 | if (prev) | ||
533 | prev->next = next; | ||
534 | else | ||
535 | fq->fragments = next; | ||
536 | |||
537 | fq->meat -= free_it->len; | ||
538 | frag_kfree_skb(free_it); | ||
539 | } | ||
540 | } | ||
541 | |||
542 | NFCT_FRAG6_CB(skb)->offset = offset; | ||
543 | |||
544 | /* Insert this fragment in the chain of fragments. */ | ||
545 | skb->next = next; | ||
546 | if (prev) | ||
547 | prev->next = skb; | ||
548 | else | ||
549 | fq->fragments = skb; | ||
550 | |||
551 | skb->dev = NULL; | ||
552 | skb_get_timestamp(skb, &fq->stamp); | ||
553 | fq->meat += skb->len; | ||
554 | atomic_add(skb->truesize, &nf_ct_frag6_mem); | ||
555 | |||
556 | /* The first fragment. | ||
557 | * nhoffset is obtained from the first fragment, of course. | ||
558 | */ | ||
559 | if (offset == 0) { | ||
560 | fq->nhoffset = nhoff; | ||
561 | fq->last_in |= FIRST_IN; | ||
562 | } | ||
563 | write_lock(&nf_ct_frag6_lock); | ||
564 | list_move_tail(&fq->lru_list, &nf_ct_frag6_lru_list); | ||
565 | write_unlock(&nf_ct_frag6_lock); | ||
566 | return 0; | ||
567 | |||
568 | err: | ||
569 | return -1; | ||
570 | } | ||
571 | |||
572 | /* | ||
573 | * Check if this packet is complete. | ||
574 | * Returns NULL on failure by any reason, and pointer | ||
575 | * to current nexthdr field in reassembled frame. | ||
576 | * | ||
577 | * It is called with locked fq, and caller must check that | ||
578 | * queue is eligible for reassembly i.e. it is not COMPLETE, | ||
579 | * the last and the first frames arrived and all the bits are here. | ||
580 | */ | ||
581 | static struct sk_buff * | ||
582 | nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) | ||
583 | { | ||
584 | struct sk_buff *fp, *op, *head = fq->fragments; | ||
585 | int payload_len; | ||
586 | |||
587 | fq_kill(fq); | ||
588 | |||
589 | BUG_TRAP(head != NULL); | ||
590 | BUG_TRAP(NFCT_FRAG6_CB(head)->offset == 0); | ||
591 | |||
592 | /* Unfragmented part is taken from the first segment. */ | ||
593 | payload_len = (head->data - head->nh.raw) - sizeof(struct ipv6hdr) + fq->len - sizeof(struct frag_hdr); | ||
594 | if (payload_len > IPV6_MAXPLEN) { | ||
595 | DEBUGP("payload len is too large.\n"); | ||
596 | goto out_oversize; | ||
597 | } | ||
598 | |||
599 | /* Head of list must not be cloned. */ | ||
600 | if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC)) { | ||
601 | DEBUGP("skb is cloned but can't expand head"); | ||
602 | goto out_oom; | ||
603 | } | ||
604 | |||
605 | /* If the first fragment is fragmented itself, we split | ||
606 | * it to two chunks: the first with data and paged part | ||
607 | * and the second, holding only fragments. */ | ||
608 | if (skb_shinfo(head)->frag_list) { | ||
609 | struct sk_buff *clone; | ||
610 | int i, plen = 0; | ||
611 | |||
612 | if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL) { | ||
613 | DEBUGP("Can't alloc skb\n"); | ||
614 | goto out_oom; | ||
615 | } | ||
616 | clone->next = head->next; | ||
617 | head->next = clone; | ||
618 | skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list; | ||
619 | skb_shinfo(head)->frag_list = NULL; | ||
620 | for (i=0; i<skb_shinfo(head)->nr_frags; i++) | ||
621 | plen += skb_shinfo(head)->frags[i].size; | ||
622 | clone->len = clone->data_len = head->data_len - plen; | ||
623 | head->data_len -= clone->len; | ||
624 | head->len -= clone->len; | ||
625 | clone->csum = 0; | ||
626 | clone->ip_summed = head->ip_summed; | ||
627 | |||
628 | NFCT_FRAG6_CB(clone)->orig = NULL; | ||
629 | atomic_add(clone->truesize, &nf_ct_frag6_mem); | ||
630 | } | ||
631 | |||
632 | /* We have to remove fragment header from datagram and to relocate | ||
633 | * header in order to calculate ICV correctly. */ | ||
634 | head->nh.raw[fq->nhoffset] = head->h.raw[0]; | ||
635 | memmove(head->head + sizeof(struct frag_hdr), head->head, | ||
636 | (head->data - head->head) - sizeof(struct frag_hdr)); | ||
637 | head->mac.raw += sizeof(struct frag_hdr); | ||
638 | head->nh.raw += sizeof(struct frag_hdr); | ||
639 | |||
640 | skb_shinfo(head)->frag_list = head->next; | ||
641 | head->h.raw = head->data; | ||
642 | skb_push(head, head->data - head->nh.raw); | ||
643 | atomic_sub(head->truesize, &nf_ct_frag6_mem); | ||
644 | |||
645 | for (fp=head->next; fp; fp = fp->next) { | ||
646 | head->data_len += fp->len; | ||
647 | head->len += fp->len; | ||
648 | if (head->ip_summed != fp->ip_summed) | ||
649 | head->ip_summed = CHECKSUM_NONE; | ||
650 | else if (head->ip_summed == CHECKSUM_HW) | ||
651 | head->csum = csum_add(head->csum, fp->csum); | ||
652 | head->truesize += fp->truesize; | ||
653 | atomic_sub(fp->truesize, &nf_ct_frag6_mem); | ||
654 | } | ||
655 | |||
656 | head->next = NULL; | ||
657 | head->dev = dev; | ||
658 | skb_set_timestamp(head, &fq->stamp); | ||
659 | head->nh.ipv6h->payload_len = htons(payload_len); | ||
660 | |||
661 | /* Yes, and fold redundant checksum back. 8) */ | ||
662 | if (head->ip_summed == CHECKSUM_HW) | ||
663 | head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum); | ||
664 | |||
665 | fq->fragments = NULL; | ||
666 | |||
667 | /* all original skbs are linked into the NFCT_FRAG6_CB(head).orig */ | ||
668 | fp = skb_shinfo(head)->frag_list; | ||
669 | if (NFCT_FRAG6_CB(fp)->orig == NULL) | ||
670 | /* at above code, head skb is divided into two skbs. */ | ||
671 | fp = fp->next; | ||
672 | |||
673 | op = NFCT_FRAG6_CB(head)->orig; | ||
674 | for (; fp; fp = fp->next) { | ||
675 | struct sk_buff *orig = NFCT_FRAG6_CB(fp)->orig; | ||
676 | |||
677 | op->next = orig; | ||
678 | op = orig; | ||
679 | NFCT_FRAG6_CB(fp)->orig = NULL; | ||
680 | } | ||
681 | |||
682 | return head; | ||
683 | |||
684 | out_oversize: | ||
685 | if (net_ratelimit()) | ||
686 | printk(KERN_DEBUG "nf_ct_frag6_reasm: payload len = %d\n", payload_len); | ||
687 | goto out_fail; | ||
688 | out_oom: | ||
689 | if (net_ratelimit()) | ||
690 | printk(KERN_DEBUG "nf_ct_frag6_reasm: no memory for reassembly\n"); | ||
691 | out_fail: | ||
692 | return NULL; | ||
693 | } | ||
694 | |||
695 | /* | ||
696 | * find the header just before Fragment Header. | ||
697 | * | ||
698 | * if success return 0 and set ... | ||
699 | * (*prevhdrp): the value of "Next Header Field" in the header | ||
700 | * just before Fragment Header. | ||
701 | * (*prevhoff): the offset of "Next Header Field" in the header | ||
702 | * just before Fragment Header. | ||
703 | * (*fhoff) : the offset of Fragment Header. | ||
704 | * | ||
705 | * Based on ipv6_skip_hdr() in net/ipv6/exthdr.c | ||
706 | * | ||
707 | */ | ||
708 | static int | ||
709 | find_prev_fhdr(struct sk_buff *skb, u8 *prevhdrp, int *prevhoff, int *fhoff) | ||
710 | { | ||
711 | u8 nexthdr = skb->nh.ipv6h->nexthdr; | ||
712 | u8 prev_nhoff = (u8 *)&skb->nh.ipv6h->nexthdr - skb->data; | ||
713 | int start = (u8 *)(skb->nh.ipv6h+1) - skb->data; | ||
714 | int len = skb->len - start; | ||
715 | u8 prevhdr = NEXTHDR_IPV6; | ||
716 | |||
717 | while (nexthdr != NEXTHDR_FRAGMENT) { | ||
718 | struct ipv6_opt_hdr hdr; | ||
719 | int hdrlen; | ||
720 | |||
721 | if (!ipv6_ext_hdr(nexthdr)) { | ||
722 | return -1; | ||
723 | } | ||
724 | if (len < (int)sizeof(struct ipv6_opt_hdr)) { | ||
725 | DEBUGP("too short\n"); | ||
726 | return -1; | ||
727 | } | ||
728 | if (nexthdr == NEXTHDR_NONE) { | ||
729 | DEBUGP("next header is none\n"); | ||
730 | return -1; | ||
731 | } | ||
732 | if (skb_copy_bits(skb, start, &hdr, sizeof(hdr))) | ||
733 | BUG(); | ||
734 | if (nexthdr == NEXTHDR_AUTH) | ||
735 | hdrlen = (hdr.hdrlen+2)<<2; | ||
736 | else | ||
737 | hdrlen = ipv6_optlen(&hdr); | ||
738 | |||
739 | prevhdr = nexthdr; | ||
740 | prev_nhoff = start; | ||
741 | |||
742 | nexthdr = hdr.nexthdr; | ||
743 | len -= hdrlen; | ||
744 | start += hdrlen; | ||
745 | } | ||
746 | |||
747 | if (len < 0) | ||
748 | return -1; | ||
749 | |||
750 | *prevhdrp = prevhdr; | ||
751 | *prevhoff = prev_nhoff; | ||
752 | *fhoff = start; | ||
753 | |||
754 | return 0; | ||
755 | } | ||
756 | |||
757 | struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb) | ||
758 | { | ||
759 | struct sk_buff *clone; | ||
760 | struct net_device *dev = skb->dev; | ||
761 | struct frag_hdr *fhdr; | ||
762 | struct nf_ct_frag6_queue *fq; | ||
763 | struct ipv6hdr *hdr; | ||
764 | int fhoff, nhoff; | ||
765 | u8 prevhdr; | ||
766 | struct sk_buff *ret_skb = NULL; | ||
767 | |||
768 | /* Jumbo payload inhibits frag. header */ | ||
769 | if (skb->nh.ipv6h->payload_len == 0) { | ||
770 | DEBUGP("payload len = 0\n"); | ||
771 | return skb; | ||
772 | } | ||
773 | |||
774 | if (find_prev_fhdr(skb, &prevhdr, &nhoff, &fhoff) < 0) | ||
775 | return skb; | ||
776 | |||
777 | clone = skb_clone(skb, GFP_ATOMIC); | ||
778 | if (clone == NULL) { | ||
779 | DEBUGP("Can't clone skb\n"); | ||
780 | return skb; | ||
781 | } | ||
782 | |||
783 | NFCT_FRAG6_CB(clone)->orig = skb; | ||
784 | |||
785 | if (!pskb_may_pull(clone, fhoff + sizeof(*fhdr))) { | ||
786 | DEBUGP("message is too short.\n"); | ||
787 | goto ret_orig; | ||
788 | } | ||
789 | |||
790 | clone->h.raw = clone->data + fhoff; | ||
791 | hdr = clone->nh.ipv6h; | ||
792 | fhdr = (struct frag_hdr *)clone->h.raw; | ||
793 | |||
794 | if (!(fhdr->frag_off & htons(0xFFF9))) { | ||
795 | DEBUGP("Invalid fragment offset\n"); | ||
796 | /* It is not a fragmented frame */ | ||
797 | goto ret_orig; | ||
798 | } | ||
799 | |||
800 | if (atomic_read(&nf_ct_frag6_mem) > nf_ct_frag6_high_thresh) | ||
801 | nf_ct_frag6_evictor(); | ||
802 | |||
803 | fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr); | ||
804 | if (fq == NULL) { | ||
805 | DEBUGP("Can't find and can't create new queue\n"); | ||
806 | goto ret_orig; | ||
807 | } | ||
808 | |||
809 | spin_lock(&fq->lock); | ||
810 | |||
811 | if (nf_ct_frag6_queue(fq, clone, fhdr, nhoff) < 0) { | ||
812 | spin_unlock(&fq->lock); | ||
813 | DEBUGP("Can't insert skb to queue\n"); | ||
814 | fq_put(fq); | ||
815 | goto ret_orig; | ||
816 | } | ||
817 | |||
818 | if (fq->last_in == (FIRST_IN|LAST_IN) && fq->meat == fq->len) { | ||
819 | ret_skb = nf_ct_frag6_reasm(fq, dev); | ||
820 | if (ret_skb == NULL) | ||
821 | DEBUGP("Can't reassemble fragmented packets\n"); | ||
822 | } | ||
823 | spin_unlock(&fq->lock); | ||
824 | |||
825 | fq_put(fq); | ||
826 | return ret_skb; | ||
827 | |||
828 | ret_orig: | ||
829 | kfree_skb(clone); | ||
830 | return skb; | ||
831 | } | ||
832 | |||
833 | void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb, | ||
834 | struct net_device *in, struct net_device *out, | ||
835 | int (*okfn)(struct sk_buff *)) | ||
836 | { | ||
837 | struct sk_buff *s, *s2; | ||
838 | |||
839 | for (s = NFCT_FRAG6_CB(skb)->orig; s;) { | ||
840 | nf_conntrack_put_reasm(s->nfct_reasm); | ||
841 | nf_conntrack_get_reasm(skb); | ||
842 | s->nfct_reasm = skb; | ||
843 | |||
844 | s2 = s->next; | ||
845 | NF_HOOK_THRESH(PF_INET6, hooknum, s, in, out, okfn, | ||
846 | NF_IP6_PRI_CONNTRACK_DEFRAG + 1); | ||
847 | s = s2; | ||
848 | } | ||
849 | nf_conntrack_put_reasm(skb); | ||
850 | } | ||
851 | |||
852 | int nf_ct_frag6_kfree_frags(struct sk_buff *skb) | ||
853 | { | ||
854 | struct sk_buff *s, *s2; | ||
855 | |||
856 | for (s = NFCT_FRAG6_CB(skb)->orig; s; s = s2) { | ||
857 | |||
858 | s2 = s->next; | ||
859 | kfree_skb(s); | ||
860 | } | ||
861 | |||
862 | kfree_skb(skb); | ||
863 | |||
864 | return 0; | ||
865 | } | ||
866 | |||
867 | int nf_ct_frag6_init(void) | ||
868 | { | ||
869 | nf_ct_frag6_hash_rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^ | ||
870 | (jiffies ^ (jiffies >> 6))); | ||
871 | |||
872 | init_timer(&nf_ct_frag6_secret_timer); | ||
873 | nf_ct_frag6_secret_timer.function = nf_ct_frag6_secret_rebuild; | ||
874 | nf_ct_frag6_secret_timer.expires = jiffies | ||
875 | + nf_ct_frag6_secret_interval; | ||
876 | add_timer(&nf_ct_frag6_secret_timer); | ||
877 | |||
878 | return 0; | ||
879 | } | ||
880 | |||
881 | void nf_ct_frag6_cleanup(void) | ||
882 | { | ||
883 | del_timer(&nf_ct_frag6_secret_timer); | ||
884 | nf_ct_frag6_evictor(); | ||
885 | } | ||
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index a1265a320b11..8e9628f1c4c5 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -174,8 +174,10 @@ int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) | |||
174 | struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); | 174 | struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); |
175 | 175 | ||
176 | /* Not releasing hash table! */ | 176 | /* Not releasing hash table! */ |
177 | if (clone) | 177 | if (clone) { |
178 | nf_reset(clone); | ||
178 | rawv6_rcv(sk, clone); | 179 | rawv6_rcv(sk, clone); |
180 | } | ||
179 | } | 181 | } |
180 | sk = __raw_v6_lookup(sk_next(sk), nexthdr, daddr, saddr, | 182 | sk = __raw_v6_lookup(sk_next(sk), nexthdr, daddr, saddr, |
181 | IP6CB(skb)->iif); | 183 | IP6CB(skb)->iif); |
@@ -296,13 +298,10 @@ void rawv6_err(struct sock *sk, struct sk_buff *skb, | |||
296 | static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) | 298 | static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) |
297 | { | 299 | { |
298 | if ((raw6_sk(sk)->checksum || sk->sk_filter) && | 300 | if ((raw6_sk(sk)->checksum || sk->sk_filter) && |
299 | skb->ip_summed != CHECKSUM_UNNECESSARY) { | 301 | skb_checksum_complete(skb)) { |
300 | if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) { | 302 | /* FIXME: increment a raw6 drops counter here */ |
301 | /* FIXME: increment a raw6 drops counter here */ | 303 | kfree_skb(skb); |
302 | kfree_skb(skb); | 304 | return 0; |
303 | return 0; | ||
304 | } | ||
305 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
306 | } | 305 | } |
307 | 306 | ||
308 | /* Charge it to the socket. */ | 307 | /* Charge it to the socket. */ |
@@ -335,32 +334,25 @@ int rawv6_rcv(struct sock *sk, struct sk_buff *skb) | |||
335 | if (!rp->checksum) | 334 | if (!rp->checksum) |
336 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 335 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
337 | 336 | ||
338 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) { | 337 | if (skb->ip_summed == CHECKSUM_HW) { |
339 | if (skb->ip_summed == CHECKSUM_HW) { | 338 | skb_postpull_rcsum(skb, skb->nh.raw, |
340 | skb_postpull_rcsum(skb, skb->nh.raw, | 339 | skb->h.raw - skb->nh.raw); |
341 | skb->h.raw - skb->nh.raw); | 340 | if (!csum_ipv6_magic(&skb->nh.ipv6h->saddr, |
341 | &skb->nh.ipv6h->daddr, | ||
342 | skb->len, inet->num, skb->csum)) | ||
342 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 343 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
343 | if (csum_ipv6_magic(&skb->nh.ipv6h->saddr, | ||
344 | &skb->nh.ipv6h->daddr, | ||
345 | skb->len, inet->num, skb->csum)) { | ||
346 | LIMIT_NETDEBUG(KERN_DEBUG "raw v6 hw csum failure.\n"); | ||
347 | skb->ip_summed = CHECKSUM_NONE; | ||
348 | } | ||
349 | } | ||
350 | if (skb->ip_summed == CHECKSUM_NONE) | ||
351 | skb->csum = ~csum_ipv6_magic(&skb->nh.ipv6h->saddr, | ||
352 | &skb->nh.ipv6h->daddr, | ||
353 | skb->len, inet->num, 0); | ||
354 | } | 344 | } |
345 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) | ||
346 | skb->csum = ~csum_ipv6_magic(&skb->nh.ipv6h->saddr, | ||
347 | &skb->nh.ipv6h->daddr, | ||
348 | skb->len, inet->num, 0); | ||
355 | 349 | ||
356 | if (inet->hdrincl) { | 350 | if (inet->hdrincl) { |
357 | if (skb->ip_summed != CHECKSUM_UNNECESSARY && | 351 | if (skb_checksum_complete(skb)) { |
358 | (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) { | ||
359 | /* FIXME: increment a raw6 drops counter here */ | 352 | /* FIXME: increment a raw6 drops counter here */ |
360 | kfree_skb(skb); | 353 | kfree_skb(skb); |
361 | return 0; | 354 | return 0; |
362 | } | 355 | } |
363 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
364 | } | 356 | } |
365 | 357 | ||
366 | rawv6_rcv_skb(sk, skb); | 358 | rawv6_rcv_skb(sk, skb); |
@@ -405,7 +397,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
405 | if (skb->ip_summed==CHECKSUM_UNNECESSARY) { | 397 | if (skb->ip_summed==CHECKSUM_UNNECESSARY) { |
406 | err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); | 398 | err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); |
407 | } else if (msg->msg_flags&MSG_TRUNC) { | 399 | } else if (msg->msg_flags&MSG_TRUNC) { |
408 | if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) | 400 | if (__skb_checksum_complete(skb)) |
409 | goto csum_copy_err; | 401 | goto csum_copy_err; |
410 | err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); | 402 | err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); |
411 | } else { | 403 | } else { |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 227e99ed510c..f7f42c3e96cb 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -1710,7 +1710,7 @@ static void fib6_dump_end(struct netlink_callback *cb) | |||
1710 | static int fib6_dump_done(struct netlink_callback *cb) | 1710 | static int fib6_dump_done(struct netlink_callback *cb) |
1711 | { | 1711 | { |
1712 | fib6_dump_end(cb); | 1712 | fib6_dump_end(cb); |
1713 | return cb->done(cb); | 1713 | return cb->done ? cb->done(cb) : 0; |
1714 | } | 1714 | } |
1715 | 1715 | ||
1716 | int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) | 1716 | int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index d746d3b27efb..62c0e5bd931c 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -1401,20 +1401,18 @@ out: | |||
1401 | static int tcp_v6_checksum_init(struct sk_buff *skb) | 1401 | static int tcp_v6_checksum_init(struct sk_buff *skb) |
1402 | { | 1402 | { |
1403 | if (skb->ip_summed == CHECKSUM_HW) { | 1403 | if (skb->ip_summed == CHECKSUM_HW) { |
1404 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
1405 | if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, | 1404 | if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, |
1406 | &skb->nh.ipv6h->daddr,skb->csum)) | 1405 | &skb->nh.ipv6h->daddr,skb->csum)) { |
1406 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
1407 | return 0; | 1407 | return 0; |
1408 | LIMIT_NETDEBUG(KERN_DEBUG "hw tcp v6 csum failed\n"); | 1408 | } |
1409 | } | 1409 | } |
1410 | |||
1411 | skb->csum = ~tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, | ||
1412 | &skb->nh.ipv6h->daddr, 0); | ||
1413 | |||
1410 | if (skb->len <= 76) { | 1414 | if (skb->len <= 76) { |
1411 | if (tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, | 1415 | return __skb_checksum_complete(skb); |
1412 | &skb->nh.ipv6h->daddr,skb_checksum(skb, 0, skb->len, 0))) | ||
1413 | return -1; | ||
1414 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
1415 | } else { | ||
1416 | skb->csum = ~tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, | ||
1417 | &skb->nh.ipv6h->daddr,0); | ||
1418 | } | 1416 | } |
1419 | return 0; | 1417 | return 0; |
1420 | } | 1418 | } |
@@ -1575,7 +1573,7 @@ static int tcp_v6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) | |||
1575 | goto discard_it; | 1573 | goto discard_it; |
1576 | 1574 | ||
1577 | if ((skb->ip_summed != CHECKSUM_UNNECESSARY && | 1575 | if ((skb->ip_summed != CHECKSUM_UNNECESSARY && |
1578 | tcp_v6_checksum_init(skb) < 0)) | 1576 | tcp_v6_checksum_init(skb))) |
1579 | goto bad_packet; | 1577 | goto bad_packet; |
1580 | 1578 | ||
1581 | th = skb->h.th; | 1579 | th = skb->h.th; |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index bf9519341fd3..e671153b47b2 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -248,7 +248,7 @@ try_again: | |||
248 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, | 248 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, |
249 | copied); | 249 | copied); |
250 | } else if (msg->msg_flags&MSG_TRUNC) { | 250 | } else if (msg->msg_flags&MSG_TRUNC) { |
251 | if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) | 251 | if (__skb_checksum_complete(skb)) |
252 | goto csum_copy_err; | 252 | goto csum_copy_err; |
253 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, | 253 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, |
254 | copied); | 254 | copied); |
@@ -363,13 +363,10 @@ static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | |||
363 | return -1; | 363 | return -1; |
364 | } | 364 | } |
365 | 365 | ||
366 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) { | 366 | if (skb_checksum_complete(skb)) { |
367 | if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) { | 367 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS); |
368 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS); | 368 | kfree_skb(skb); |
369 | kfree_skb(skb); | 369 | return 0; |
370 | return 0; | ||
371 | } | ||
372 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
373 | } | 370 | } |
374 | 371 | ||
375 | if (sock_queue_rcv_skb(sk,skb)<0) { | 372 | if (sock_queue_rcv_skb(sk,skb)<0) { |
@@ -491,13 +488,10 @@ static int udpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) | |||
491 | uh = skb->h.uh; | 488 | uh = skb->h.uh; |
492 | } | 489 | } |
493 | 490 | ||
494 | if (skb->ip_summed==CHECKSUM_HW) { | 491 | if (skb->ip_summed == CHECKSUM_HW && |
492 | !csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) | ||
495 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 493 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
496 | if (csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) { | 494 | |
497 | LIMIT_NETDEBUG(KERN_DEBUG "udp v6 hw csum failure.\n"); | ||
498 | skb->ip_summed = CHECKSUM_NONE; | ||
499 | } | ||
500 | } | ||
501 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) | 495 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) |
502 | skb->csum = ~csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, 0); | 496 | skb->csum = ~csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, 0); |
503 | 497 | ||
@@ -521,8 +515,7 @@ static int udpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) | |||
521 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) | 515 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) |
522 | goto discard; | 516 | goto discard; |
523 | 517 | ||
524 | if (skb->ip_summed != CHECKSUM_UNNECESSARY && | 518 | if (skb_checksum_complete(skb)) |
525 | (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) | ||
526 | goto discard; | 519 | goto discard; |
527 | UDP6_INC_STATS_BH(UDP_MIB_NOPORTS); | 520 | UDP6_INC_STATS_BH(UDP_MIB_NOPORTS); |
528 | 521 | ||
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 8296b38bf270..a84f9221e5f0 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
@@ -1,3 +1,6 @@ | |||
1 | menu "Core Netfilter Configuration" | ||
2 | depends on NET && NETFILTER | ||
3 | |||
1 | config NETFILTER_NETLINK | 4 | config NETFILTER_NETLINK |
2 | tristate "Netfilter netlink interface" | 5 | tristate "Netfilter netlink interface" |
3 | help | 6 | help |
@@ -22,3 +25,74 @@ config NETFILTER_NETLINK_LOG | |||
22 | and is also scheduled to replace the old syslog-based ipt_LOG | 25 | and is also scheduled to replace the old syslog-based ipt_LOG |
23 | and ip6t_LOG modules. | 26 | and ip6t_LOG modules. |
24 | 27 | ||
28 | config NF_CONNTRACK | ||
29 | tristate "Layer 3 Independent Connection tracking (EXPERIMENTAL)" | ||
30 | depends on EXPERIMENTAL && IP_NF_CONNTRACK=n | ||
31 | default n | ||
32 | ---help--- | ||
33 | Connection tracking keeps a record of what packets have passed | ||
34 | through your machine, in order to figure out how they are related | ||
35 | into connections. | ||
36 | |||
37 | Layer 3 independent connection tracking is experimental scheme | ||
38 | which generalize ip_conntrack to support other layer 3 protocols. | ||
39 | |||
40 | To compile it as a module, choose M here. If unsure, say N. | ||
41 | |||
42 | config NF_CT_ACCT | ||
43 | bool "Connection tracking flow accounting" | ||
44 | depends on NF_CONNTRACK | ||
45 | help | ||
46 | If this option is enabled, the connection tracking code will | ||
47 | keep per-flow packet and byte counters. | ||
48 | |||
49 | Those counters can be used for flow-based accounting or the | ||
50 | `connbytes' match. | ||
51 | |||
52 | If unsure, say `N'. | ||
53 | |||
54 | config NF_CONNTRACK_MARK | ||
55 | bool 'Connection mark tracking support' | ||
56 | depends on NF_CONNTRACK | ||
57 | help | ||
58 | This option enables support for connection marks, used by the | ||
59 | `CONNMARK' target and `connmark' match. Similar to the mark value | ||
60 | of packets, but this mark value is kept in the conntrack session | ||
61 | instead of the individual packets. | ||
62 | |||
63 | config NF_CONNTRACK_EVENTS | ||
64 | bool "Connection tracking events" | ||
65 | depends on NF_CONNTRACK | ||
66 | help | ||
67 | If this option is enabled, the connection tracking code will | ||
68 | provide a notifier chain that can be used by other kernel code | ||
69 | to get notified aboutchanges in the connection tracking state. | ||
70 | |||
71 | If unsure, say `N'. | ||
72 | |||
73 | config NF_CT_PROTO_SCTP | ||
74 | tristate 'SCTP protocol on new connection tracking support (EXPERIMENTAL)' | ||
75 | depends on EXPERIMENTAL && NF_CONNTRACK | ||
76 | default n | ||
77 | help | ||
78 | With this option enabled, the layer 3 independent connection | ||
79 | tracking code will be able to do state tracking on SCTP connections. | ||
80 | |||
81 | If you want to compile it as a module, say M here and read | ||
82 | Documentation/modules.txt. If unsure, say `N'. | ||
83 | |||
84 | config NF_CONNTRACK_FTP | ||
85 | tristate "FTP support on new connection tracking (EXPERIMENTAL)" | ||
86 | depends on EXPERIMENTAL && NF_CONNTRACK | ||
87 | help | ||
88 | Tracking FTP connections is problematic: special helpers are | ||
89 | required for tracking them, and doing masquerading and other forms | ||
90 | of Network Address Translation on them. | ||
91 | |||
92 | This is FTP support on Layer 3 independent connection tracking. | ||
93 | Layer 3 independent connection tracking is experimental scheme | ||
94 | which generalize ip_conntrack to support other layer 3 protocols. | ||
95 | |||
96 | To compile it as a module, choose M here. If unsure, say N. | ||
97 | |||
98 | endmenu | ||
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index b3b44f8b415a..55f019ad2c08 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
@@ -5,3 +5,11 @@ obj-$(CONFIG_NETFILTER) = netfilter.o | |||
5 | obj-$(CONFIG_NETFILTER_NETLINK) += nfnetlink.o | 5 | obj-$(CONFIG_NETFILTER_NETLINK) += nfnetlink.o |
6 | obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o | 6 | obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o |
7 | obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o | 7 | obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o |
8 | |||
9 | nf_conntrack-objs := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o | ||
10 | |||
11 | obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o | ||
12 | obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o | ||
13 | |||
14 | # SCTP protocol connection tracking | ||
15 | obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o | ||
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c new file mode 100644 index 000000000000..9a67c796b385 --- /dev/null +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -0,0 +1,1538 @@ | |||
1 | /* Connection state tracking for netfilter. This is separated from, | ||
2 | but required by, the NAT layer; it can also be used by an iptables | ||
3 | extension. */ | ||
4 | |||
5 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
6 | * (C) 2002-2005 Netfilter Core Team <coreteam@netfilter.org> | ||
7 | * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * 23 Apr 2001: Harald Welte <laforge@gnumonks.org> | ||
14 | * - new API and handling of conntrack/nat helpers | ||
15 | * - now capable of multiple expectations for one master | ||
16 | * 16 Jul 2002: Harald Welte <laforge@gnumonks.org> | ||
17 | * - add usage/reference counts to ip_conntrack_expect | ||
18 | * - export ip_conntrack[_expect]_{find_get,put} functions | ||
19 | * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
20 | * - generalize L3 protocol denendent part. | ||
21 | * 23 Mar 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
22 | * - add support various size of conntrack structures. | ||
23 | * | ||
24 | * Derived from net/ipv4/netfilter/ip_conntrack_core.c | ||
25 | */ | ||
26 | |||
27 | #include <linux/config.h> | ||
28 | #include <linux/types.h> | ||
29 | #include <linux/netfilter.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/skbuff.h> | ||
32 | #include <linux/proc_fs.h> | ||
33 | #include <linux/vmalloc.h> | ||
34 | #include <linux/stddef.h> | ||
35 | #include <linux/slab.h> | ||
36 | #include <linux/random.h> | ||
37 | #include <linux/jhash.h> | ||
38 | #include <linux/err.h> | ||
39 | #include <linux/percpu.h> | ||
40 | #include <linux/moduleparam.h> | ||
41 | #include <linux/notifier.h> | ||
42 | #include <linux/kernel.h> | ||
43 | #include <linux/netdevice.h> | ||
44 | #include <linux/socket.h> | ||
45 | |||
46 | /* This rwlock protects the main hash table, protocol/helper/expected | ||
47 | registrations, conntrack timers*/ | ||
48 | #define ASSERT_READ_LOCK(x) | ||
49 | #define ASSERT_WRITE_LOCK(x) | ||
50 | |||
51 | #include <net/netfilter/nf_conntrack.h> | ||
52 | #include <net/netfilter/nf_conntrack_l3proto.h> | ||
53 | #include <net/netfilter/nf_conntrack_protocol.h> | ||
54 | #include <net/netfilter/nf_conntrack_helper.h> | ||
55 | #include <net/netfilter/nf_conntrack_core.h> | ||
56 | #include <linux/netfilter_ipv4/listhelp.h> | ||
57 | |||
58 | #define NF_CONNTRACK_VERSION "0.4.1" | ||
59 | |||
60 | #if 0 | ||
61 | #define DEBUGP printk | ||
62 | #else | ||
63 | #define DEBUGP(format, args...) | ||
64 | #endif | ||
65 | |||
66 | DEFINE_RWLOCK(nf_conntrack_lock); | ||
67 | |||
68 | /* nf_conntrack_standalone needs this */ | ||
69 | atomic_t nf_conntrack_count = ATOMIC_INIT(0); | ||
70 | |||
71 | void (*nf_conntrack_destroyed)(struct nf_conn *conntrack) = NULL; | ||
72 | LIST_HEAD(nf_conntrack_expect_list); | ||
73 | struct nf_conntrack_protocol **nf_ct_protos[PF_MAX]; | ||
74 | struct nf_conntrack_l3proto *nf_ct_l3protos[PF_MAX]; | ||
75 | static LIST_HEAD(helpers); | ||
76 | unsigned int nf_conntrack_htable_size = 0; | ||
77 | int nf_conntrack_max; | ||
78 | struct list_head *nf_conntrack_hash; | ||
79 | static kmem_cache_t *nf_conntrack_expect_cachep; | ||
80 | struct nf_conn nf_conntrack_untracked; | ||
81 | unsigned int nf_ct_log_invalid; | ||
82 | static LIST_HEAD(unconfirmed); | ||
83 | static int nf_conntrack_vmalloc; | ||
84 | |||
85 | #ifdef CONFIG_NF_CONNTRACK_EVENTS | ||
86 | struct notifier_block *nf_conntrack_chain; | ||
87 | struct notifier_block *nf_conntrack_expect_chain; | ||
88 | |||
89 | DEFINE_PER_CPU(struct nf_conntrack_ecache, nf_conntrack_ecache); | ||
90 | |||
91 | /* deliver cached events and clear cache entry - must be called with locally | ||
92 | * disabled softirqs */ | ||
93 | static inline void | ||
94 | __nf_ct_deliver_cached_events(struct nf_conntrack_ecache *ecache) | ||
95 | { | ||
96 | DEBUGP("ecache: delivering events for %p\n", ecache->ct); | ||
97 | if (nf_ct_is_confirmed(ecache->ct) && !nf_ct_is_dying(ecache->ct) | ||
98 | && ecache->events) | ||
99 | notifier_call_chain(&nf_conntrack_chain, ecache->events, | ||
100 | ecache->ct); | ||
101 | |||
102 | ecache->events = 0; | ||
103 | nf_ct_put(ecache->ct); | ||
104 | ecache->ct = NULL; | ||
105 | } | ||
106 | |||
107 | /* Deliver all cached events for a particular conntrack. This is called | ||
108 | * by code prior to async packet handling for freeing the skb */ | ||
109 | void nf_ct_deliver_cached_events(const struct nf_conn *ct) | ||
110 | { | ||
111 | struct nf_conntrack_ecache *ecache; | ||
112 | |||
113 | local_bh_disable(); | ||
114 | ecache = &__get_cpu_var(nf_conntrack_ecache); | ||
115 | if (ecache->ct == ct) | ||
116 | __nf_ct_deliver_cached_events(ecache); | ||
117 | local_bh_enable(); | ||
118 | } | ||
119 | |||
120 | /* Deliver cached events for old pending events, if current conntrack != old */ | ||
121 | void __nf_ct_event_cache_init(struct nf_conn *ct) | ||
122 | { | ||
123 | struct nf_conntrack_ecache *ecache; | ||
124 | |||
125 | /* take care of delivering potentially old events */ | ||
126 | ecache = &__get_cpu_var(nf_conntrack_ecache); | ||
127 | BUG_ON(ecache->ct == ct); | ||
128 | if (ecache->ct) | ||
129 | __nf_ct_deliver_cached_events(ecache); | ||
130 | /* initialize for this conntrack/packet */ | ||
131 | ecache->ct = ct; | ||
132 | nf_conntrack_get(&ct->ct_general); | ||
133 | } | ||
134 | |||
135 | /* flush the event cache - touches other CPU's data and must not be called | ||
136 | * while packets are still passing through the code */ | ||
137 | static void nf_ct_event_cache_flush(void) | ||
138 | { | ||
139 | struct nf_conntrack_ecache *ecache; | ||
140 | int cpu; | ||
141 | |||
142 | for_each_cpu(cpu) { | ||
143 | ecache = &per_cpu(nf_conntrack_ecache, cpu); | ||
144 | if (ecache->ct) | ||
145 | nf_ct_put(ecache->ct); | ||
146 | } | ||
147 | } | ||
148 | #else | ||
149 | static inline void nf_ct_event_cache_flush(void) {} | ||
150 | #endif /* CONFIG_NF_CONNTRACK_EVENTS */ | ||
151 | |||
152 | DEFINE_PER_CPU(struct ip_conntrack_stat, nf_conntrack_stat); | ||
153 | EXPORT_PER_CPU_SYMBOL(nf_conntrack_stat); | ||
154 | |||
155 | /* | ||
156 | * This scheme offers various size of "struct nf_conn" dependent on | ||
157 | * features(helper, nat, ...) | ||
158 | */ | ||
159 | |||
160 | #define NF_CT_FEATURES_NAMELEN 256 | ||
161 | static struct { | ||
162 | /* name of slab cache. printed in /proc/slabinfo */ | ||
163 | char *name; | ||
164 | |||
165 | /* size of slab cache */ | ||
166 | size_t size; | ||
167 | |||
168 | /* slab cache pointer */ | ||
169 | kmem_cache_t *cachep; | ||
170 | |||
171 | /* allocated slab cache + modules which uses this slab cache */ | ||
172 | int use; | ||
173 | |||
174 | /* Initialization */ | ||
175 | int (*init_conntrack)(struct nf_conn *, u_int32_t); | ||
176 | |||
177 | } nf_ct_cache[NF_CT_F_NUM]; | ||
178 | |||
179 | /* protect members of nf_ct_cache except of "use" */ | ||
180 | DEFINE_RWLOCK(nf_ct_cache_lock); | ||
181 | |||
182 | /* This avoids calling kmem_cache_create() with same name simultaneously */ | ||
183 | DECLARE_MUTEX(nf_ct_cache_mutex); | ||
184 | |||
185 | extern struct nf_conntrack_protocol nf_conntrack_generic_protocol; | ||
186 | struct nf_conntrack_protocol * | ||
187 | nf_ct_find_proto(u_int16_t l3proto, u_int8_t protocol) | ||
188 | { | ||
189 | if (unlikely(nf_ct_protos[l3proto] == NULL)) | ||
190 | return &nf_conntrack_generic_protocol; | ||
191 | |||
192 | return nf_ct_protos[l3proto][protocol]; | ||
193 | } | ||
194 | |||
195 | static int nf_conntrack_hash_rnd_initted; | ||
196 | static unsigned int nf_conntrack_hash_rnd; | ||
197 | |||
198 | static u_int32_t __hash_conntrack(const struct nf_conntrack_tuple *tuple, | ||
199 | unsigned int size, unsigned int rnd) | ||
200 | { | ||
201 | unsigned int a, b; | ||
202 | a = jhash((void *)tuple->src.u3.all, sizeof(tuple->src.u3.all), | ||
203 | ((tuple->src.l3num) << 16) | tuple->dst.protonum); | ||
204 | b = jhash((void *)tuple->dst.u3.all, sizeof(tuple->dst.u3.all), | ||
205 | (tuple->src.u.all << 16) | tuple->dst.u.all); | ||
206 | |||
207 | return jhash_2words(a, b, rnd) % size; | ||
208 | } | ||
209 | |||
210 | static inline u_int32_t hash_conntrack(const struct nf_conntrack_tuple *tuple) | ||
211 | { | ||
212 | return __hash_conntrack(tuple, nf_conntrack_htable_size, | ||
213 | nf_conntrack_hash_rnd); | ||
214 | } | ||
215 | |||
216 | /* Initialize "struct nf_conn" which has spaces for helper */ | ||
217 | static int | ||
218 | init_conntrack_for_helper(struct nf_conn *conntrack, u_int32_t features) | ||
219 | { | ||
220 | |||
221 | conntrack->help = (union nf_conntrack_help *) | ||
222 | (((unsigned long)conntrack->data | ||
223 | + (__alignof__(union nf_conntrack_help) - 1)) | ||
224 | & (~((unsigned long)(__alignof__(union nf_conntrack_help) -1)))); | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | int nf_conntrack_register_cache(u_int32_t features, const char *name, | ||
229 | size_t size, | ||
230 | int (*init)(struct nf_conn *, u_int32_t)) | ||
231 | { | ||
232 | int ret = 0; | ||
233 | char *cache_name; | ||
234 | kmem_cache_t *cachep; | ||
235 | |||
236 | DEBUGP("nf_conntrack_register_cache: features=0x%x, name=%s, size=%d\n", | ||
237 | features, name, size); | ||
238 | |||
239 | if (features < NF_CT_F_BASIC || features >= NF_CT_F_NUM) { | ||
240 | DEBUGP("nf_conntrack_register_cache: invalid features.: 0x%x\n", | ||
241 | features); | ||
242 | return -EINVAL; | ||
243 | } | ||
244 | |||
245 | down(&nf_ct_cache_mutex); | ||
246 | |||
247 | write_lock_bh(&nf_ct_cache_lock); | ||
248 | /* e.g: multiple helpers are loaded */ | ||
249 | if (nf_ct_cache[features].use > 0) { | ||
250 | DEBUGP("nf_conntrack_register_cache: already resisterd.\n"); | ||
251 | if ((!strncmp(nf_ct_cache[features].name, name, | ||
252 | NF_CT_FEATURES_NAMELEN)) | ||
253 | && nf_ct_cache[features].size == size | ||
254 | && nf_ct_cache[features].init_conntrack == init) { | ||
255 | DEBUGP("nf_conntrack_register_cache: reusing.\n"); | ||
256 | nf_ct_cache[features].use++; | ||
257 | ret = 0; | ||
258 | } else | ||
259 | ret = -EBUSY; | ||
260 | |||
261 | write_unlock_bh(&nf_ct_cache_lock); | ||
262 | up(&nf_ct_cache_mutex); | ||
263 | return ret; | ||
264 | } | ||
265 | write_unlock_bh(&nf_ct_cache_lock); | ||
266 | |||
267 | /* | ||
268 | * The memory space for name of slab cache must be alive until | ||
269 | * cache is destroyed. | ||
270 | */ | ||
271 | cache_name = kmalloc(sizeof(char)*NF_CT_FEATURES_NAMELEN, GFP_ATOMIC); | ||
272 | if (cache_name == NULL) { | ||
273 | DEBUGP("nf_conntrack_register_cache: can't alloc cache_name\n"); | ||
274 | ret = -ENOMEM; | ||
275 | goto out_up_mutex; | ||
276 | } | ||
277 | |||
278 | if (strlcpy(cache_name, name, NF_CT_FEATURES_NAMELEN) | ||
279 | >= NF_CT_FEATURES_NAMELEN) { | ||
280 | printk("nf_conntrack_register_cache: name too long\n"); | ||
281 | ret = -EINVAL; | ||
282 | goto out_free_name; | ||
283 | } | ||
284 | |||
285 | cachep = kmem_cache_create(cache_name, size, 0, 0, | ||
286 | NULL, NULL); | ||
287 | if (!cachep) { | ||
288 | printk("nf_conntrack_register_cache: Can't create slab cache " | ||
289 | "for the features = 0x%x\n", features); | ||
290 | ret = -ENOMEM; | ||
291 | goto out_free_name; | ||
292 | } | ||
293 | |||
294 | write_lock_bh(&nf_ct_cache_lock); | ||
295 | nf_ct_cache[features].use = 1; | ||
296 | nf_ct_cache[features].size = size; | ||
297 | nf_ct_cache[features].init_conntrack = init; | ||
298 | nf_ct_cache[features].cachep = cachep; | ||
299 | nf_ct_cache[features].name = cache_name; | ||
300 | write_unlock_bh(&nf_ct_cache_lock); | ||
301 | |||
302 | goto out_up_mutex; | ||
303 | |||
304 | out_free_name: | ||
305 | kfree(cache_name); | ||
306 | out_up_mutex: | ||
307 | up(&nf_ct_cache_mutex); | ||
308 | return ret; | ||
309 | } | ||
310 | |||
311 | /* FIXME: In the current, only nf_conntrack_cleanup() can call this function. */ | ||
312 | void nf_conntrack_unregister_cache(u_int32_t features) | ||
313 | { | ||
314 | kmem_cache_t *cachep; | ||
315 | char *name; | ||
316 | |||
317 | /* | ||
318 | * This assures that kmem_cache_create() isn't called before destroying | ||
319 | * slab cache. | ||
320 | */ | ||
321 | DEBUGP("nf_conntrack_unregister_cache: 0x%04x\n", features); | ||
322 | down(&nf_ct_cache_mutex); | ||
323 | |||
324 | write_lock_bh(&nf_ct_cache_lock); | ||
325 | if (--nf_ct_cache[features].use > 0) { | ||
326 | write_unlock_bh(&nf_ct_cache_lock); | ||
327 | up(&nf_ct_cache_mutex); | ||
328 | return; | ||
329 | } | ||
330 | cachep = nf_ct_cache[features].cachep; | ||
331 | name = nf_ct_cache[features].name; | ||
332 | nf_ct_cache[features].cachep = NULL; | ||
333 | nf_ct_cache[features].name = NULL; | ||
334 | nf_ct_cache[features].init_conntrack = NULL; | ||
335 | nf_ct_cache[features].size = 0; | ||
336 | write_unlock_bh(&nf_ct_cache_lock); | ||
337 | |||
338 | synchronize_net(); | ||
339 | |||
340 | kmem_cache_destroy(cachep); | ||
341 | kfree(name); | ||
342 | |||
343 | up(&nf_ct_cache_mutex); | ||
344 | } | ||
345 | |||
346 | int | ||
347 | nf_ct_get_tuple(const struct sk_buff *skb, | ||
348 | unsigned int nhoff, | ||
349 | unsigned int dataoff, | ||
350 | u_int16_t l3num, | ||
351 | u_int8_t protonum, | ||
352 | struct nf_conntrack_tuple *tuple, | ||
353 | const struct nf_conntrack_l3proto *l3proto, | ||
354 | const struct nf_conntrack_protocol *protocol) | ||
355 | { | ||
356 | NF_CT_TUPLE_U_BLANK(tuple); | ||
357 | |||
358 | tuple->src.l3num = l3num; | ||
359 | if (l3proto->pkt_to_tuple(skb, nhoff, tuple) == 0) | ||
360 | return 0; | ||
361 | |||
362 | tuple->dst.protonum = protonum; | ||
363 | tuple->dst.dir = IP_CT_DIR_ORIGINAL; | ||
364 | |||
365 | return protocol->pkt_to_tuple(skb, dataoff, tuple); | ||
366 | } | ||
367 | |||
368 | int | ||
369 | nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse, | ||
370 | const struct nf_conntrack_tuple *orig, | ||
371 | const struct nf_conntrack_l3proto *l3proto, | ||
372 | const struct nf_conntrack_protocol *protocol) | ||
373 | { | ||
374 | NF_CT_TUPLE_U_BLANK(inverse); | ||
375 | |||
376 | inverse->src.l3num = orig->src.l3num; | ||
377 | if (l3proto->invert_tuple(inverse, orig) == 0) | ||
378 | return 0; | ||
379 | |||
380 | inverse->dst.dir = !orig->dst.dir; | ||
381 | |||
382 | inverse->dst.protonum = orig->dst.protonum; | ||
383 | return protocol->invert_tuple(inverse, orig); | ||
384 | } | ||
385 | |||
386 | /* nf_conntrack_expect helper functions */ | ||
387 | static void nf_ct_unlink_expect(struct nf_conntrack_expect *exp) | ||
388 | { | ||
389 | ASSERT_WRITE_LOCK(&nf_conntrack_lock); | ||
390 | NF_CT_ASSERT(!timer_pending(&exp_timeout)); | ||
391 | list_del(&exp->list); | ||
392 | NF_CT_STAT_INC(expect_delete); | ||
393 | exp->master->expecting--; | ||
394 | nf_conntrack_expect_put(exp); | ||
395 | } | ||
396 | |||
397 | static void expectation_timed_out(unsigned long ul_expect) | ||
398 | { | ||
399 | struct nf_conntrack_expect *exp = (void *)ul_expect; | ||
400 | |||
401 | write_lock_bh(&nf_conntrack_lock); | ||
402 | nf_ct_unlink_expect(exp); | ||
403 | write_unlock_bh(&nf_conntrack_lock); | ||
404 | nf_conntrack_expect_put(exp); | ||
405 | } | ||
406 | |||
407 | /* If an expectation for this connection is found, it gets delete from | ||
408 | * global list then returned. */ | ||
409 | static struct nf_conntrack_expect * | ||
410 | find_expectation(const struct nf_conntrack_tuple *tuple) | ||
411 | { | ||
412 | struct nf_conntrack_expect *i; | ||
413 | |||
414 | list_for_each_entry(i, &nf_conntrack_expect_list, list) { | ||
415 | /* If master is not in hash table yet (ie. packet hasn't left | ||
416 | this machine yet), how can other end know about expected? | ||
417 | Hence these are not the droids you are looking for (if | ||
418 | master ct never got confirmed, we'd hold a reference to it | ||
419 | and weird things would happen to future packets). */ | ||
420 | if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) | ||
421 | && nf_ct_is_confirmed(i->master)) { | ||
422 | if (i->flags & NF_CT_EXPECT_PERMANENT) { | ||
423 | atomic_inc(&i->use); | ||
424 | return i; | ||
425 | } else if (del_timer(&i->timeout)) { | ||
426 | nf_ct_unlink_expect(i); | ||
427 | return i; | ||
428 | } | ||
429 | } | ||
430 | } | ||
431 | return NULL; | ||
432 | } | ||
433 | |||
434 | /* delete all expectations for this conntrack */ | ||
435 | static void remove_expectations(struct nf_conn *ct) | ||
436 | { | ||
437 | struct nf_conntrack_expect *i, *tmp; | ||
438 | |||
439 | /* Optimization: most connection never expect any others. */ | ||
440 | if (ct->expecting == 0) | ||
441 | return; | ||
442 | |||
443 | list_for_each_entry_safe(i, tmp, &nf_conntrack_expect_list, list) { | ||
444 | if (i->master == ct && del_timer(&i->timeout)) { | ||
445 | nf_ct_unlink_expect(i); | ||
446 | nf_conntrack_expect_put(i); | ||
447 | } | ||
448 | } | ||
449 | } | ||
450 | |||
451 | static void | ||
452 | clean_from_lists(struct nf_conn *ct) | ||
453 | { | ||
454 | unsigned int ho, hr; | ||
455 | |||
456 | DEBUGP("clean_from_lists(%p)\n", ct); | ||
457 | ASSERT_WRITE_LOCK(&nf_conntrack_lock); | ||
458 | |||
459 | ho = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | ||
460 | hr = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); | ||
461 | LIST_DELETE(&nf_conntrack_hash[ho], &ct->tuplehash[IP_CT_DIR_ORIGINAL]); | ||
462 | LIST_DELETE(&nf_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]); | ||
463 | |||
464 | /* Destroy all pending expectations */ | ||
465 | remove_expectations(ct); | ||
466 | } | ||
467 | |||
468 | static void | ||
469 | destroy_conntrack(struct nf_conntrack *nfct) | ||
470 | { | ||
471 | struct nf_conn *ct = (struct nf_conn *)nfct; | ||
472 | struct nf_conntrack_l3proto *l3proto; | ||
473 | struct nf_conntrack_protocol *proto; | ||
474 | |||
475 | DEBUGP("destroy_conntrack(%p)\n", ct); | ||
476 | NF_CT_ASSERT(atomic_read(&nfct->use) == 0); | ||
477 | NF_CT_ASSERT(!timer_pending(&ct->timeout)); | ||
478 | |||
479 | nf_conntrack_event(IPCT_DESTROY, ct); | ||
480 | set_bit(IPS_DYING_BIT, &ct->status); | ||
481 | |||
482 | /* To make sure we don't get any weird locking issues here: | ||
483 | * destroy_conntrack() MUST NOT be called with a write lock | ||
484 | * to nf_conntrack_lock!!! -HW */ | ||
485 | l3proto = nf_ct_find_l3proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num); | ||
486 | if (l3proto && l3proto->destroy) | ||
487 | l3proto->destroy(ct); | ||
488 | |||
489 | proto = nf_ct_find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num, | ||
490 | ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum); | ||
491 | if (proto && proto->destroy) | ||
492 | proto->destroy(ct); | ||
493 | |||
494 | if (nf_conntrack_destroyed) | ||
495 | nf_conntrack_destroyed(ct); | ||
496 | |||
497 | write_lock_bh(&nf_conntrack_lock); | ||
498 | /* Expectations will have been removed in clean_from_lists, | ||
499 | * except TFTP can create an expectation on the first packet, | ||
500 | * before connection is in the list, so we need to clean here, | ||
501 | * too. */ | ||
502 | remove_expectations(ct); | ||
503 | |||
504 | /* We overload first tuple to link into unconfirmed list. */ | ||
505 | if (!nf_ct_is_confirmed(ct)) { | ||
506 | BUG_ON(list_empty(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list)); | ||
507 | list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); | ||
508 | } | ||
509 | |||
510 | NF_CT_STAT_INC(delete); | ||
511 | write_unlock_bh(&nf_conntrack_lock); | ||
512 | |||
513 | if (ct->master) | ||
514 | nf_ct_put(ct->master); | ||
515 | |||
516 | DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct); | ||
517 | nf_conntrack_free(ct); | ||
518 | } | ||
519 | |||
520 | static void death_by_timeout(unsigned long ul_conntrack) | ||
521 | { | ||
522 | struct nf_conn *ct = (void *)ul_conntrack; | ||
523 | |||
524 | write_lock_bh(&nf_conntrack_lock); | ||
525 | /* Inside lock so preempt is disabled on module removal path. | ||
526 | * Otherwise we can get spurious warnings. */ | ||
527 | NF_CT_STAT_INC(delete_list); | ||
528 | clean_from_lists(ct); | ||
529 | write_unlock_bh(&nf_conntrack_lock); | ||
530 | nf_ct_put(ct); | ||
531 | } | ||
532 | |||
533 | static inline int | ||
534 | conntrack_tuple_cmp(const struct nf_conntrack_tuple_hash *i, | ||
535 | const struct nf_conntrack_tuple *tuple, | ||
536 | const struct nf_conn *ignored_conntrack) | ||
537 | { | ||
538 | ASSERT_READ_LOCK(&nf_conntrack_lock); | ||
539 | return nf_ct_tuplehash_to_ctrack(i) != ignored_conntrack | ||
540 | && nf_ct_tuple_equal(tuple, &i->tuple); | ||
541 | } | ||
542 | |||
543 | static struct nf_conntrack_tuple_hash * | ||
544 | __nf_conntrack_find(const struct nf_conntrack_tuple *tuple, | ||
545 | const struct nf_conn *ignored_conntrack) | ||
546 | { | ||
547 | struct nf_conntrack_tuple_hash *h; | ||
548 | unsigned int hash = hash_conntrack(tuple); | ||
549 | |||
550 | ASSERT_READ_LOCK(&nf_conntrack_lock); | ||
551 | list_for_each_entry(h, &nf_conntrack_hash[hash], list) { | ||
552 | if (conntrack_tuple_cmp(h, tuple, ignored_conntrack)) { | ||
553 | NF_CT_STAT_INC(found); | ||
554 | return h; | ||
555 | } | ||
556 | NF_CT_STAT_INC(searched); | ||
557 | } | ||
558 | |||
559 | return NULL; | ||
560 | } | ||
561 | |||
562 | /* Find a connection corresponding to a tuple. */ | ||
563 | struct nf_conntrack_tuple_hash * | ||
564 | nf_conntrack_find_get(const struct nf_conntrack_tuple *tuple, | ||
565 | const struct nf_conn *ignored_conntrack) | ||
566 | { | ||
567 | struct nf_conntrack_tuple_hash *h; | ||
568 | |||
569 | read_lock_bh(&nf_conntrack_lock); | ||
570 | h = __nf_conntrack_find(tuple, ignored_conntrack); | ||
571 | if (h) | ||
572 | atomic_inc(&nf_ct_tuplehash_to_ctrack(h)->ct_general.use); | ||
573 | read_unlock_bh(&nf_conntrack_lock); | ||
574 | |||
575 | return h; | ||
576 | } | ||
577 | |||
578 | /* Confirm a connection given skb; places it in hash table */ | ||
579 | int | ||
580 | __nf_conntrack_confirm(struct sk_buff **pskb) | ||
581 | { | ||
582 | unsigned int hash, repl_hash; | ||
583 | struct nf_conn *ct; | ||
584 | enum ip_conntrack_info ctinfo; | ||
585 | |||
586 | ct = nf_ct_get(*pskb, &ctinfo); | ||
587 | |||
588 | /* ipt_REJECT uses nf_conntrack_attach to attach related | ||
589 | ICMP/TCP RST packets in other direction. Actual packet | ||
590 | which created connection will be IP_CT_NEW or for an | ||
591 | expected connection, IP_CT_RELATED. */ | ||
592 | if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL) | ||
593 | return NF_ACCEPT; | ||
594 | |||
595 | hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | ||
596 | repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); | ||
597 | |||
598 | /* We're not in hash table, and we refuse to set up related | ||
599 | connections for unconfirmed conns. But packet copies and | ||
600 | REJECT will give spurious warnings here. */ | ||
601 | /* NF_CT_ASSERT(atomic_read(&ct->ct_general.use) == 1); */ | ||
602 | |||
603 | /* No external references means noone else could have | ||
604 | confirmed us. */ | ||
605 | NF_CT_ASSERT(!nf_ct_is_confirmed(ct)); | ||
606 | DEBUGP("Confirming conntrack %p\n", ct); | ||
607 | |||
608 | write_lock_bh(&nf_conntrack_lock); | ||
609 | |||
610 | /* See if there's one in the list already, including reverse: | ||
611 | NAT could have grabbed it without realizing, since we're | ||
612 | not in the hash. If there is, we lost race. */ | ||
613 | if (!LIST_FIND(&nf_conntrack_hash[hash], | ||
614 | conntrack_tuple_cmp, | ||
615 | struct nf_conntrack_tuple_hash *, | ||
616 | &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, NULL) | ||
617 | && !LIST_FIND(&nf_conntrack_hash[repl_hash], | ||
618 | conntrack_tuple_cmp, | ||
619 | struct nf_conntrack_tuple_hash *, | ||
620 | &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) { | ||
621 | /* Remove from unconfirmed list */ | ||
622 | list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); | ||
623 | |||
624 | list_prepend(&nf_conntrack_hash[hash], | ||
625 | &ct->tuplehash[IP_CT_DIR_ORIGINAL]); | ||
626 | list_prepend(&nf_conntrack_hash[repl_hash], | ||
627 | &ct->tuplehash[IP_CT_DIR_REPLY]); | ||
628 | /* Timer relative to confirmation time, not original | ||
629 | setting time, otherwise we'd get timer wrap in | ||
630 | weird delay cases. */ | ||
631 | ct->timeout.expires += jiffies; | ||
632 | add_timer(&ct->timeout); | ||
633 | atomic_inc(&ct->ct_general.use); | ||
634 | set_bit(IPS_CONFIRMED_BIT, &ct->status); | ||
635 | NF_CT_STAT_INC(insert); | ||
636 | write_unlock_bh(&nf_conntrack_lock); | ||
637 | if (ct->helper) | ||
638 | nf_conntrack_event_cache(IPCT_HELPER, *pskb); | ||
639 | #ifdef CONFIG_NF_NAT_NEEDED | ||
640 | if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) || | ||
641 | test_bit(IPS_DST_NAT_DONE_BIT, &ct->status)) | ||
642 | nf_conntrack_event_cache(IPCT_NATINFO, *pskb); | ||
643 | #endif | ||
644 | nf_conntrack_event_cache(master_ct(ct) ? | ||
645 | IPCT_RELATED : IPCT_NEW, *pskb); | ||
646 | return NF_ACCEPT; | ||
647 | } | ||
648 | |||
649 | NF_CT_STAT_INC(insert_failed); | ||
650 | write_unlock_bh(&nf_conntrack_lock); | ||
651 | return NF_DROP; | ||
652 | } | ||
653 | |||
654 | /* Returns true if a connection correspondings to the tuple (required | ||
655 | for NAT). */ | ||
656 | int | ||
657 | nf_conntrack_tuple_taken(const struct nf_conntrack_tuple *tuple, | ||
658 | const struct nf_conn *ignored_conntrack) | ||
659 | { | ||
660 | struct nf_conntrack_tuple_hash *h; | ||
661 | |||
662 | read_lock_bh(&nf_conntrack_lock); | ||
663 | h = __nf_conntrack_find(tuple, ignored_conntrack); | ||
664 | read_unlock_bh(&nf_conntrack_lock); | ||
665 | |||
666 | return h != NULL; | ||
667 | } | ||
668 | |||
669 | /* There's a small race here where we may free a just-assured | ||
670 | connection. Too bad: we're in trouble anyway. */ | ||
671 | static inline int unreplied(const struct nf_conntrack_tuple_hash *i) | ||
672 | { | ||
673 | return !(test_bit(IPS_ASSURED_BIT, | ||
674 | &nf_ct_tuplehash_to_ctrack(i)->status)); | ||
675 | } | ||
676 | |||
677 | static int early_drop(struct list_head *chain) | ||
678 | { | ||
679 | /* Traverse backwards: gives us oldest, which is roughly LRU */ | ||
680 | struct nf_conntrack_tuple_hash *h; | ||
681 | struct nf_conn *ct = NULL; | ||
682 | int dropped = 0; | ||
683 | |||
684 | read_lock_bh(&nf_conntrack_lock); | ||
685 | h = LIST_FIND_B(chain, unreplied, struct nf_conntrack_tuple_hash *); | ||
686 | if (h) { | ||
687 | ct = nf_ct_tuplehash_to_ctrack(h); | ||
688 | atomic_inc(&ct->ct_general.use); | ||
689 | } | ||
690 | read_unlock_bh(&nf_conntrack_lock); | ||
691 | |||
692 | if (!ct) | ||
693 | return dropped; | ||
694 | |||
695 | if (del_timer(&ct->timeout)) { | ||
696 | death_by_timeout((unsigned long)ct); | ||
697 | dropped = 1; | ||
698 | NF_CT_STAT_INC(early_drop); | ||
699 | } | ||
700 | nf_ct_put(ct); | ||
701 | return dropped; | ||
702 | } | ||
703 | |||
704 | static inline int helper_cmp(const struct nf_conntrack_helper *i, | ||
705 | const struct nf_conntrack_tuple *rtuple) | ||
706 | { | ||
707 | return nf_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask); | ||
708 | } | ||
709 | |||
710 | static struct nf_conntrack_helper * | ||
711 | nf_ct_find_helper(const struct nf_conntrack_tuple *tuple) | ||
712 | { | ||
713 | return LIST_FIND(&helpers, helper_cmp, | ||
714 | struct nf_conntrack_helper *, | ||
715 | tuple); | ||
716 | } | ||
717 | |||
718 | static struct nf_conn * | ||
719 | __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, | ||
720 | const struct nf_conntrack_tuple *repl, | ||
721 | const struct nf_conntrack_l3proto *l3proto) | ||
722 | { | ||
723 | struct nf_conn *conntrack = NULL; | ||
724 | u_int32_t features = 0; | ||
725 | |||
726 | if (!nf_conntrack_hash_rnd_initted) { | ||
727 | get_random_bytes(&nf_conntrack_hash_rnd, 4); | ||
728 | nf_conntrack_hash_rnd_initted = 1; | ||
729 | } | ||
730 | |||
731 | if (nf_conntrack_max | ||
732 | && atomic_read(&nf_conntrack_count) >= nf_conntrack_max) { | ||
733 | unsigned int hash = hash_conntrack(orig); | ||
734 | /* Try dropping from this hash chain. */ | ||
735 | if (!early_drop(&nf_conntrack_hash[hash])) { | ||
736 | if (net_ratelimit()) | ||
737 | printk(KERN_WARNING | ||
738 | "nf_conntrack: table full, dropping" | ||
739 | " packet.\n"); | ||
740 | return ERR_PTR(-ENOMEM); | ||
741 | } | ||
742 | } | ||
743 | |||
744 | /* find features needed by this conntrack. */ | ||
745 | features = l3proto->get_features(orig); | ||
746 | read_lock_bh(&nf_conntrack_lock); | ||
747 | if (nf_ct_find_helper(repl) != NULL) | ||
748 | features |= NF_CT_F_HELP; | ||
749 | read_unlock_bh(&nf_conntrack_lock); | ||
750 | |||
751 | DEBUGP("nf_conntrack_alloc: features=0x%x\n", features); | ||
752 | |||
753 | read_lock_bh(&nf_ct_cache_lock); | ||
754 | |||
755 | if (!nf_ct_cache[features].use) { | ||
756 | DEBUGP("nf_conntrack_alloc: not supported features = 0x%x\n", | ||
757 | features); | ||
758 | goto out; | ||
759 | } | ||
760 | |||
761 | conntrack = kmem_cache_alloc(nf_ct_cache[features].cachep, GFP_ATOMIC); | ||
762 | if (conntrack == NULL) { | ||
763 | DEBUGP("nf_conntrack_alloc: Can't alloc conntrack from cache\n"); | ||
764 | goto out; | ||
765 | } | ||
766 | |||
767 | memset(conntrack, 0, nf_ct_cache[features].size); | ||
768 | conntrack->features = features; | ||
769 | if (nf_ct_cache[features].init_conntrack && | ||
770 | nf_ct_cache[features].init_conntrack(conntrack, features) < 0) { | ||
771 | DEBUGP("nf_conntrack_alloc: failed to init\n"); | ||
772 | kmem_cache_free(nf_ct_cache[features].cachep, conntrack); | ||
773 | conntrack = NULL; | ||
774 | goto out; | ||
775 | } | ||
776 | |||
777 | atomic_set(&conntrack->ct_general.use, 1); | ||
778 | conntrack->ct_general.destroy = destroy_conntrack; | ||
779 | conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig; | ||
780 | conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *repl; | ||
781 | /* Don't set timer yet: wait for confirmation */ | ||
782 | init_timer(&conntrack->timeout); | ||
783 | conntrack->timeout.data = (unsigned long)conntrack; | ||
784 | conntrack->timeout.function = death_by_timeout; | ||
785 | |||
786 | atomic_inc(&nf_conntrack_count); | ||
787 | out: | ||
788 | read_unlock_bh(&nf_ct_cache_lock); | ||
789 | return conntrack; | ||
790 | } | ||
791 | |||
792 | struct nf_conn *nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, | ||
793 | const struct nf_conntrack_tuple *repl) | ||
794 | { | ||
795 | struct nf_conntrack_l3proto *l3proto; | ||
796 | |||
797 | l3proto = nf_ct_find_l3proto(orig->src.l3num); | ||
798 | return __nf_conntrack_alloc(orig, repl, l3proto); | ||
799 | } | ||
800 | |||
801 | void nf_conntrack_free(struct nf_conn *conntrack) | ||
802 | { | ||
803 | u_int32_t features = conntrack->features; | ||
804 | NF_CT_ASSERT(features >= NF_CT_F_BASIC && features < NF_CT_F_NUM); | ||
805 | DEBUGP("nf_conntrack_free: features = 0x%x, conntrack=%p\n", features, | ||
806 | conntrack); | ||
807 | kmem_cache_free(nf_ct_cache[features].cachep, conntrack); | ||
808 | atomic_dec(&nf_conntrack_count); | ||
809 | } | ||
810 | |||
811 | /* Allocate a new conntrack: we return -ENOMEM if classification | ||
812 | failed due to stress. Otherwise it really is unclassifiable. */ | ||
813 | static struct nf_conntrack_tuple_hash * | ||
814 | init_conntrack(const struct nf_conntrack_tuple *tuple, | ||
815 | struct nf_conntrack_l3proto *l3proto, | ||
816 | struct nf_conntrack_protocol *protocol, | ||
817 | struct sk_buff *skb, | ||
818 | unsigned int dataoff) | ||
819 | { | ||
820 | struct nf_conn *conntrack; | ||
821 | struct nf_conntrack_tuple repl_tuple; | ||
822 | struct nf_conntrack_expect *exp; | ||
823 | |||
824 | if (!nf_ct_invert_tuple(&repl_tuple, tuple, l3proto, protocol)) { | ||
825 | DEBUGP("Can't invert tuple.\n"); | ||
826 | return NULL; | ||
827 | } | ||
828 | |||
829 | conntrack = __nf_conntrack_alloc(tuple, &repl_tuple, l3proto); | ||
830 | if (conntrack == NULL || IS_ERR(conntrack)) { | ||
831 | DEBUGP("Can't allocate conntrack.\n"); | ||
832 | return (struct nf_conntrack_tuple_hash *)conntrack; | ||
833 | } | ||
834 | |||
835 | if (!protocol->new(conntrack, skb, dataoff)) { | ||
836 | nf_conntrack_free(conntrack); | ||
837 | DEBUGP("init conntrack: can't track with proto module\n"); | ||
838 | return NULL; | ||
839 | } | ||
840 | |||
841 | write_lock_bh(&nf_conntrack_lock); | ||
842 | exp = find_expectation(tuple); | ||
843 | |||
844 | if (exp) { | ||
845 | DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n", | ||
846 | conntrack, exp); | ||
847 | /* Welcome, Mr. Bond. We've been expecting you... */ | ||
848 | __set_bit(IPS_EXPECTED_BIT, &conntrack->status); | ||
849 | conntrack->master = exp->master; | ||
850 | #ifdef CONFIG_NF_CONNTRACK_MARK | ||
851 | conntrack->mark = exp->master->mark; | ||
852 | #endif | ||
853 | nf_conntrack_get(&conntrack->master->ct_general); | ||
854 | NF_CT_STAT_INC(expect_new); | ||
855 | } else { | ||
856 | conntrack->helper = nf_ct_find_helper(&repl_tuple); | ||
857 | |||
858 | NF_CT_STAT_INC(new); | ||
859 | } | ||
860 | |||
861 | /* Overload tuple linked list to put us in unconfirmed list. */ | ||
862 | list_add(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list, &unconfirmed); | ||
863 | |||
864 | write_unlock_bh(&nf_conntrack_lock); | ||
865 | |||
866 | if (exp) { | ||
867 | if (exp->expectfn) | ||
868 | exp->expectfn(conntrack, exp); | ||
869 | nf_conntrack_expect_put(exp); | ||
870 | } | ||
871 | |||
872 | return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL]; | ||
873 | } | ||
874 | |||
875 | /* On success, returns conntrack ptr, sets skb->nfct and ctinfo */ | ||
876 | static inline struct nf_conn * | ||
877 | resolve_normal_ct(struct sk_buff *skb, | ||
878 | unsigned int dataoff, | ||
879 | u_int16_t l3num, | ||
880 | u_int8_t protonum, | ||
881 | struct nf_conntrack_l3proto *l3proto, | ||
882 | struct nf_conntrack_protocol *proto, | ||
883 | int *set_reply, | ||
884 | enum ip_conntrack_info *ctinfo) | ||
885 | { | ||
886 | struct nf_conntrack_tuple tuple; | ||
887 | struct nf_conntrack_tuple_hash *h; | ||
888 | struct nf_conn *ct; | ||
889 | |||
890 | if (!nf_ct_get_tuple(skb, (unsigned int)(skb->nh.raw - skb->data), | ||
891 | dataoff, l3num, protonum, &tuple, l3proto, | ||
892 | proto)) { | ||
893 | DEBUGP("resolve_normal_ct: Can't get tuple\n"); | ||
894 | return NULL; | ||
895 | } | ||
896 | |||
897 | /* look for tuple match */ | ||
898 | h = nf_conntrack_find_get(&tuple, NULL); | ||
899 | if (!h) { | ||
900 | h = init_conntrack(&tuple, l3proto, proto, skb, dataoff); | ||
901 | if (!h) | ||
902 | return NULL; | ||
903 | if (IS_ERR(h)) | ||
904 | return (void *)h; | ||
905 | } | ||
906 | ct = nf_ct_tuplehash_to_ctrack(h); | ||
907 | |||
908 | /* It exists; we have (non-exclusive) reference. */ | ||
909 | if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) { | ||
910 | *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY; | ||
911 | /* Please set reply bit if this packet OK */ | ||
912 | *set_reply = 1; | ||
913 | } else { | ||
914 | /* Once we've had two way comms, always ESTABLISHED. */ | ||
915 | if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { | ||
916 | DEBUGP("nf_conntrack_in: normal packet for %p\n", ct); | ||
917 | *ctinfo = IP_CT_ESTABLISHED; | ||
918 | } else if (test_bit(IPS_EXPECTED_BIT, &ct->status)) { | ||
919 | DEBUGP("nf_conntrack_in: related packet for %p\n", ct); | ||
920 | *ctinfo = IP_CT_RELATED; | ||
921 | } else { | ||
922 | DEBUGP("nf_conntrack_in: new packet for %p\n", ct); | ||
923 | *ctinfo = IP_CT_NEW; | ||
924 | } | ||
925 | *set_reply = 0; | ||
926 | } | ||
927 | skb->nfct = &ct->ct_general; | ||
928 | skb->nfctinfo = *ctinfo; | ||
929 | return ct; | ||
930 | } | ||
931 | |||
932 | unsigned int | ||
933 | nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb) | ||
934 | { | ||
935 | struct nf_conn *ct; | ||
936 | enum ip_conntrack_info ctinfo; | ||
937 | struct nf_conntrack_l3proto *l3proto; | ||
938 | struct nf_conntrack_protocol *proto; | ||
939 | unsigned int dataoff; | ||
940 | u_int8_t protonum; | ||
941 | int set_reply = 0; | ||
942 | int ret; | ||
943 | |||
944 | /* Previously seen (loopback or untracked)? Ignore. */ | ||
945 | if ((*pskb)->nfct) { | ||
946 | NF_CT_STAT_INC(ignore); | ||
947 | return NF_ACCEPT; | ||
948 | } | ||
949 | |||
950 | l3proto = nf_ct_find_l3proto((u_int16_t)pf); | ||
951 | if ((ret = l3proto->prepare(pskb, hooknum, &dataoff, &protonum)) <= 0) { | ||
952 | DEBUGP("not prepared to track yet or error occured\n"); | ||
953 | return -ret; | ||
954 | } | ||
955 | |||
956 | proto = nf_ct_find_proto((u_int16_t)pf, protonum); | ||
957 | |||
958 | /* It may be an special packet, error, unclean... | ||
959 | * inverse of the return code tells to the netfilter | ||
960 | * core what to do with the packet. */ | ||
961 | if (proto->error != NULL && | ||
962 | (ret = proto->error(*pskb, dataoff, &ctinfo, pf, hooknum)) <= 0) { | ||
963 | NF_CT_STAT_INC(error); | ||
964 | NF_CT_STAT_INC(invalid); | ||
965 | return -ret; | ||
966 | } | ||
967 | |||
968 | ct = resolve_normal_ct(*pskb, dataoff, pf, protonum, l3proto, proto, | ||
969 | &set_reply, &ctinfo); | ||
970 | if (!ct) { | ||
971 | /* Not valid part of a connection */ | ||
972 | NF_CT_STAT_INC(invalid); | ||
973 | return NF_ACCEPT; | ||
974 | } | ||
975 | |||
976 | if (IS_ERR(ct)) { | ||
977 | /* Too stressed to deal. */ | ||
978 | NF_CT_STAT_INC(drop); | ||
979 | return NF_DROP; | ||
980 | } | ||
981 | |||
982 | NF_CT_ASSERT((*pskb)->nfct); | ||
983 | |||
984 | ret = proto->packet(ct, *pskb, dataoff, ctinfo, pf, hooknum); | ||
985 | if (ret < 0) { | ||
986 | /* Invalid: inverse of the return code tells | ||
987 | * the netfilter core what to do */ | ||
988 | DEBUGP("nf_conntrack_in: Can't track with proto module\n"); | ||
989 | nf_conntrack_put((*pskb)->nfct); | ||
990 | (*pskb)->nfct = NULL; | ||
991 | NF_CT_STAT_INC(invalid); | ||
992 | return -ret; | ||
993 | } | ||
994 | |||
995 | if (set_reply && !test_and_set_bit(IPS_SEEN_REPLY_BIT, &ct->status)) | ||
996 | nf_conntrack_event_cache(IPCT_STATUS, *pskb); | ||
997 | |||
998 | return ret; | ||
999 | } | ||
1000 | |||
1001 | int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse, | ||
1002 | const struct nf_conntrack_tuple *orig) | ||
1003 | { | ||
1004 | return nf_ct_invert_tuple(inverse, orig, | ||
1005 | nf_ct_find_l3proto(orig->src.l3num), | ||
1006 | nf_ct_find_proto(orig->src.l3num, | ||
1007 | orig->dst.protonum)); | ||
1008 | } | ||
1009 | |||
1010 | /* Would two expected things clash? */ | ||
1011 | static inline int expect_clash(const struct nf_conntrack_expect *a, | ||
1012 | const struct nf_conntrack_expect *b) | ||
1013 | { | ||
1014 | /* Part covered by intersection of masks must be unequal, | ||
1015 | otherwise they clash */ | ||
1016 | struct nf_conntrack_tuple intersect_mask; | ||
1017 | int count; | ||
1018 | |||
1019 | intersect_mask.src.l3num = a->mask.src.l3num & b->mask.src.l3num; | ||
1020 | intersect_mask.src.u.all = a->mask.src.u.all & b->mask.src.u.all; | ||
1021 | intersect_mask.dst.u.all = a->mask.dst.u.all & b->mask.dst.u.all; | ||
1022 | intersect_mask.dst.protonum = a->mask.dst.protonum | ||
1023 | & b->mask.dst.protonum; | ||
1024 | |||
1025 | for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){ | ||
1026 | intersect_mask.src.u3.all[count] = | ||
1027 | a->mask.src.u3.all[count] & b->mask.src.u3.all[count]; | ||
1028 | } | ||
1029 | |||
1030 | for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){ | ||
1031 | intersect_mask.dst.u3.all[count] = | ||
1032 | a->mask.dst.u3.all[count] & b->mask.dst.u3.all[count]; | ||
1033 | } | ||
1034 | |||
1035 | return nf_ct_tuple_mask_cmp(&a->tuple, &b->tuple, &intersect_mask); | ||
1036 | } | ||
1037 | |||
1038 | static inline int expect_matches(const struct nf_conntrack_expect *a, | ||
1039 | const struct nf_conntrack_expect *b) | ||
1040 | { | ||
1041 | return a->master == b->master | ||
1042 | && nf_ct_tuple_equal(&a->tuple, &b->tuple) | ||
1043 | && nf_ct_tuple_equal(&a->mask, &b->mask); | ||
1044 | } | ||
1045 | |||
1046 | /* Generally a bad idea to call this: could have matched already. */ | ||
1047 | void nf_conntrack_unexpect_related(struct nf_conntrack_expect *exp) | ||
1048 | { | ||
1049 | struct nf_conntrack_expect *i; | ||
1050 | |||
1051 | write_lock_bh(&nf_conntrack_lock); | ||
1052 | /* choose the the oldest expectation to evict */ | ||
1053 | list_for_each_entry_reverse(i, &nf_conntrack_expect_list, list) { | ||
1054 | if (expect_matches(i, exp) && del_timer(&i->timeout)) { | ||
1055 | nf_ct_unlink_expect(i); | ||
1056 | write_unlock_bh(&nf_conntrack_lock); | ||
1057 | nf_conntrack_expect_put(i); | ||
1058 | return; | ||
1059 | } | ||
1060 | } | ||
1061 | write_unlock_bh(&nf_conntrack_lock); | ||
1062 | } | ||
1063 | |||
1064 | /* We don't increase the master conntrack refcount for non-fulfilled | ||
1065 | * conntracks. During the conntrack destruction, the expectations are | ||
1066 | * always killed before the conntrack itself */ | ||
1067 | struct nf_conntrack_expect *nf_conntrack_expect_alloc(struct nf_conn *me) | ||
1068 | { | ||
1069 | struct nf_conntrack_expect *new; | ||
1070 | |||
1071 | new = kmem_cache_alloc(nf_conntrack_expect_cachep, GFP_ATOMIC); | ||
1072 | if (!new) { | ||
1073 | DEBUGP("expect_related: OOM allocating expect\n"); | ||
1074 | return NULL; | ||
1075 | } | ||
1076 | new->master = me; | ||
1077 | atomic_set(&new->use, 1); | ||
1078 | return new; | ||
1079 | } | ||
1080 | |||
1081 | void nf_conntrack_expect_put(struct nf_conntrack_expect *exp) | ||
1082 | { | ||
1083 | if (atomic_dec_and_test(&exp->use)) | ||
1084 | kmem_cache_free(nf_conntrack_expect_cachep, exp); | ||
1085 | } | ||
1086 | |||
1087 | static void nf_conntrack_expect_insert(struct nf_conntrack_expect *exp) | ||
1088 | { | ||
1089 | atomic_inc(&exp->use); | ||
1090 | exp->master->expecting++; | ||
1091 | list_add(&exp->list, &nf_conntrack_expect_list); | ||
1092 | |||
1093 | init_timer(&exp->timeout); | ||
1094 | exp->timeout.data = (unsigned long)exp; | ||
1095 | exp->timeout.function = expectation_timed_out; | ||
1096 | exp->timeout.expires = jiffies + exp->master->helper->timeout * HZ; | ||
1097 | add_timer(&exp->timeout); | ||
1098 | |||
1099 | atomic_inc(&exp->use); | ||
1100 | NF_CT_STAT_INC(expect_create); | ||
1101 | } | ||
1102 | |||
1103 | /* Race with expectations being used means we could have none to find; OK. */ | ||
1104 | static void evict_oldest_expect(struct nf_conn *master) | ||
1105 | { | ||
1106 | struct nf_conntrack_expect *i; | ||
1107 | |||
1108 | list_for_each_entry_reverse(i, &nf_conntrack_expect_list, list) { | ||
1109 | if (i->master == master) { | ||
1110 | if (del_timer(&i->timeout)) { | ||
1111 | nf_ct_unlink_expect(i); | ||
1112 | nf_conntrack_expect_put(i); | ||
1113 | } | ||
1114 | break; | ||
1115 | } | ||
1116 | } | ||
1117 | } | ||
1118 | |||
1119 | static inline int refresh_timer(struct nf_conntrack_expect *i) | ||
1120 | { | ||
1121 | if (!del_timer(&i->timeout)) | ||
1122 | return 0; | ||
1123 | |||
1124 | i->timeout.expires = jiffies + i->master->helper->timeout*HZ; | ||
1125 | add_timer(&i->timeout); | ||
1126 | return 1; | ||
1127 | } | ||
1128 | |||
1129 | int nf_conntrack_expect_related(struct nf_conntrack_expect *expect) | ||
1130 | { | ||
1131 | struct nf_conntrack_expect *i; | ||
1132 | int ret; | ||
1133 | |||
1134 | DEBUGP("nf_conntrack_expect_related %p\n", related_to); | ||
1135 | DEBUGP("tuple: "); NF_CT_DUMP_TUPLE(&expect->tuple); | ||
1136 | DEBUGP("mask: "); NF_CT_DUMP_TUPLE(&expect->mask); | ||
1137 | |||
1138 | write_lock_bh(&nf_conntrack_lock); | ||
1139 | list_for_each_entry(i, &nf_conntrack_expect_list, list) { | ||
1140 | if (expect_matches(i, expect)) { | ||
1141 | /* Refresh timer: if it's dying, ignore.. */ | ||
1142 | if (refresh_timer(i)) { | ||
1143 | ret = 0; | ||
1144 | goto out; | ||
1145 | } | ||
1146 | } else if (expect_clash(i, expect)) { | ||
1147 | ret = -EBUSY; | ||
1148 | goto out; | ||
1149 | } | ||
1150 | } | ||
1151 | /* Will be over limit? */ | ||
1152 | if (expect->master->helper->max_expected && | ||
1153 | expect->master->expecting >= expect->master->helper->max_expected) | ||
1154 | evict_oldest_expect(expect->master); | ||
1155 | |||
1156 | nf_conntrack_expect_insert(expect); | ||
1157 | nf_conntrack_expect_event(IPEXP_NEW, expect); | ||
1158 | ret = 0; | ||
1159 | out: | ||
1160 | write_unlock_bh(&nf_conntrack_lock); | ||
1161 | return ret; | ||
1162 | } | ||
1163 | |||
1164 | /* Alter reply tuple (maybe alter helper). This is for NAT, and is | ||
1165 | implicitly racy: see __nf_conntrack_confirm */ | ||
1166 | void nf_conntrack_alter_reply(struct nf_conn *conntrack, | ||
1167 | const struct nf_conntrack_tuple *newreply) | ||
1168 | { | ||
1169 | write_lock_bh(&nf_conntrack_lock); | ||
1170 | /* Should be unconfirmed, so not in hash table yet */ | ||
1171 | NF_CT_ASSERT(!nf_ct_is_confirmed(conntrack)); | ||
1172 | |||
1173 | DEBUGP("Altering reply tuple of %p to ", conntrack); | ||
1174 | NF_CT_DUMP_TUPLE(newreply); | ||
1175 | |||
1176 | conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; | ||
1177 | if (!conntrack->master && conntrack->expecting == 0) | ||
1178 | conntrack->helper = nf_ct_find_helper(newreply); | ||
1179 | write_unlock_bh(&nf_conntrack_lock); | ||
1180 | } | ||
1181 | |||
1182 | int nf_conntrack_helper_register(struct nf_conntrack_helper *me) | ||
1183 | { | ||
1184 | int ret; | ||
1185 | BUG_ON(me->timeout == 0); | ||
1186 | |||
1187 | ret = nf_conntrack_register_cache(NF_CT_F_HELP, "nf_conntrack:help", | ||
1188 | sizeof(struct nf_conn) | ||
1189 | + sizeof(union nf_conntrack_help) | ||
1190 | + __alignof__(union nf_conntrack_help), | ||
1191 | init_conntrack_for_helper); | ||
1192 | if (ret < 0) { | ||
1193 | printk(KERN_ERR "nf_conntrack_helper_reigster: Unable to create slab cache for conntracks\n"); | ||
1194 | return ret; | ||
1195 | } | ||
1196 | write_lock_bh(&nf_conntrack_lock); | ||
1197 | list_prepend(&helpers, me); | ||
1198 | write_unlock_bh(&nf_conntrack_lock); | ||
1199 | |||
1200 | return 0; | ||
1201 | } | ||
1202 | |||
1203 | static inline int unhelp(struct nf_conntrack_tuple_hash *i, | ||
1204 | const struct nf_conntrack_helper *me) | ||
1205 | { | ||
1206 | if (nf_ct_tuplehash_to_ctrack(i)->helper == me) { | ||
1207 | nf_conntrack_event(IPCT_HELPER, nf_ct_tuplehash_to_ctrack(i)); | ||
1208 | nf_ct_tuplehash_to_ctrack(i)->helper = NULL; | ||
1209 | } | ||
1210 | return 0; | ||
1211 | } | ||
1212 | |||
1213 | void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me) | ||
1214 | { | ||
1215 | unsigned int i; | ||
1216 | struct nf_conntrack_expect *exp, *tmp; | ||
1217 | |||
1218 | /* Need write lock here, to delete helper. */ | ||
1219 | write_lock_bh(&nf_conntrack_lock); | ||
1220 | LIST_DELETE(&helpers, me); | ||
1221 | |||
1222 | /* Get rid of expectations */ | ||
1223 | list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, list) { | ||
1224 | if (exp->master->helper == me && del_timer(&exp->timeout)) { | ||
1225 | nf_ct_unlink_expect(exp); | ||
1226 | nf_conntrack_expect_put(exp); | ||
1227 | } | ||
1228 | } | ||
1229 | |||
1230 | /* Get rid of expecteds, set helpers to NULL. */ | ||
1231 | LIST_FIND_W(&unconfirmed, unhelp, struct nf_conntrack_tuple_hash*, me); | ||
1232 | for (i = 0; i < nf_conntrack_htable_size; i++) | ||
1233 | LIST_FIND_W(&nf_conntrack_hash[i], unhelp, | ||
1234 | struct nf_conntrack_tuple_hash *, me); | ||
1235 | write_unlock_bh(&nf_conntrack_lock); | ||
1236 | |||
1237 | /* Someone could be still looking at the helper in a bh. */ | ||
1238 | synchronize_net(); | ||
1239 | } | ||
1240 | |||
1241 | /* Refresh conntrack for this many jiffies and do accounting if do_acct is 1 */ | ||
1242 | void __nf_ct_refresh_acct(struct nf_conn *ct, | ||
1243 | enum ip_conntrack_info ctinfo, | ||
1244 | const struct sk_buff *skb, | ||
1245 | unsigned long extra_jiffies, | ||
1246 | int do_acct) | ||
1247 | { | ||
1248 | int event = 0; | ||
1249 | |||
1250 | NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct); | ||
1251 | NF_CT_ASSERT(skb); | ||
1252 | |||
1253 | write_lock_bh(&nf_conntrack_lock); | ||
1254 | |||
1255 | /* If not in hash table, timer will not be active yet */ | ||
1256 | if (!nf_ct_is_confirmed(ct)) { | ||
1257 | ct->timeout.expires = extra_jiffies; | ||
1258 | event = IPCT_REFRESH; | ||
1259 | } else { | ||
1260 | /* Need del_timer for race avoidance (may already be dying). */ | ||
1261 | if (del_timer(&ct->timeout)) { | ||
1262 | ct->timeout.expires = jiffies + extra_jiffies; | ||
1263 | add_timer(&ct->timeout); | ||
1264 | event = IPCT_REFRESH; | ||
1265 | } | ||
1266 | } | ||
1267 | |||
1268 | #ifdef CONFIG_NF_CT_ACCT | ||
1269 | if (do_acct) { | ||
1270 | ct->counters[CTINFO2DIR(ctinfo)].packets++; | ||
1271 | ct->counters[CTINFO2DIR(ctinfo)].bytes += | ||
1272 | skb->len - (unsigned int)(skb->nh.raw - skb->data); | ||
1273 | if ((ct->counters[CTINFO2DIR(ctinfo)].packets & 0x80000000) | ||
1274 | || (ct->counters[CTINFO2DIR(ctinfo)].bytes & 0x80000000)) | ||
1275 | event |= IPCT_COUNTER_FILLING; | ||
1276 | } | ||
1277 | #endif | ||
1278 | |||
1279 | write_unlock_bh(&nf_conntrack_lock); | ||
1280 | |||
1281 | /* must be unlocked when calling event cache */ | ||
1282 | if (event) | ||
1283 | nf_conntrack_event_cache(event, skb); | ||
1284 | } | ||
1285 | |||
1286 | /* Used by ipt_REJECT and ip6t_REJECT. */ | ||
1287 | void __nf_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb) | ||
1288 | { | ||
1289 | struct nf_conn *ct; | ||
1290 | enum ip_conntrack_info ctinfo; | ||
1291 | |||
1292 | /* This ICMP is in reverse direction to the packet which caused it */ | ||
1293 | ct = nf_ct_get(skb, &ctinfo); | ||
1294 | if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) | ||
1295 | ctinfo = IP_CT_RELATED + IP_CT_IS_REPLY; | ||
1296 | else | ||
1297 | ctinfo = IP_CT_RELATED; | ||
1298 | |||
1299 | /* Attach to new skbuff, and increment count */ | ||
1300 | nskb->nfct = &ct->ct_general; | ||
1301 | nskb->nfctinfo = ctinfo; | ||
1302 | nf_conntrack_get(nskb->nfct); | ||
1303 | } | ||
1304 | |||
1305 | static inline int | ||
1306 | do_iter(const struct nf_conntrack_tuple_hash *i, | ||
1307 | int (*iter)(struct nf_conn *i, void *data), | ||
1308 | void *data) | ||
1309 | { | ||
1310 | return iter(nf_ct_tuplehash_to_ctrack(i), data); | ||
1311 | } | ||
1312 | |||
1313 | /* Bring out ya dead! */ | ||
1314 | static struct nf_conntrack_tuple_hash * | ||
1315 | get_next_corpse(int (*iter)(struct nf_conn *i, void *data), | ||
1316 | void *data, unsigned int *bucket) | ||
1317 | { | ||
1318 | struct nf_conntrack_tuple_hash *h = NULL; | ||
1319 | |||
1320 | write_lock_bh(&nf_conntrack_lock); | ||
1321 | for (; *bucket < nf_conntrack_htable_size; (*bucket)++) { | ||
1322 | h = LIST_FIND_W(&nf_conntrack_hash[*bucket], do_iter, | ||
1323 | struct nf_conntrack_tuple_hash *, iter, data); | ||
1324 | if (h) | ||
1325 | break; | ||
1326 | } | ||
1327 | if (!h) | ||
1328 | h = LIST_FIND_W(&unconfirmed, do_iter, | ||
1329 | struct nf_conntrack_tuple_hash *, iter, data); | ||
1330 | if (h) | ||
1331 | atomic_inc(&nf_ct_tuplehash_to_ctrack(h)->ct_general.use); | ||
1332 | write_unlock_bh(&nf_conntrack_lock); | ||
1333 | |||
1334 | return h; | ||
1335 | } | ||
1336 | |||
1337 | void | ||
1338 | nf_ct_iterate_cleanup(int (*iter)(struct nf_conn *i, void *data), void *data) | ||
1339 | { | ||
1340 | struct nf_conntrack_tuple_hash *h; | ||
1341 | unsigned int bucket = 0; | ||
1342 | |||
1343 | while ((h = get_next_corpse(iter, data, &bucket)) != NULL) { | ||
1344 | struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); | ||
1345 | /* Time to push up daises... */ | ||
1346 | if (del_timer(&ct->timeout)) | ||
1347 | death_by_timeout((unsigned long)ct); | ||
1348 | /* ... else the timer will get him soon. */ | ||
1349 | |||
1350 | nf_ct_put(ct); | ||
1351 | } | ||
1352 | } | ||
1353 | |||
1354 | static int kill_all(struct nf_conn *i, void *data) | ||
1355 | { | ||
1356 | return 1; | ||
1357 | } | ||
1358 | |||
1359 | static void free_conntrack_hash(struct list_head *hash, int vmalloced, int size) | ||
1360 | { | ||
1361 | if (vmalloced) | ||
1362 | vfree(hash); | ||
1363 | else | ||
1364 | free_pages((unsigned long)hash, | ||
1365 | get_order(sizeof(struct list_head) * size)); | ||
1366 | } | ||
1367 | |||
1368 | /* Mishearing the voices in his head, our hero wonders how he's | ||
1369 | supposed to kill the mall. */ | ||
1370 | void nf_conntrack_cleanup(void) | ||
1371 | { | ||
1372 | int i; | ||
1373 | |||
1374 | /* This makes sure all current packets have passed through | ||
1375 | netfilter framework. Roll on, two-stage module | ||
1376 | delete... */ | ||
1377 | synchronize_net(); | ||
1378 | |||
1379 | nf_ct_event_cache_flush(); | ||
1380 | i_see_dead_people: | ||
1381 | nf_ct_iterate_cleanup(kill_all, NULL); | ||
1382 | if (atomic_read(&nf_conntrack_count) != 0) { | ||
1383 | schedule(); | ||
1384 | goto i_see_dead_people; | ||
1385 | } | ||
1386 | |||
1387 | for (i = 0; i < NF_CT_F_NUM; i++) { | ||
1388 | if (nf_ct_cache[i].use == 0) | ||
1389 | continue; | ||
1390 | |||
1391 | NF_CT_ASSERT(nf_ct_cache[i].use == 1); | ||
1392 | nf_ct_cache[i].use = 1; | ||
1393 | nf_conntrack_unregister_cache(i); | ||
1394 | } | ||
1395 | kmem_cache_destroy(nf_conntrack_expect_cachep); | ||
1396 | free_conntrack_hash(nf_conntrack_hash, nf_conntrack_vmalloc, | ||
1397 | nf_conntrack_htable_size); | ||
1398 | } | ||
1399 | |||
1400 | static struct list_head *alloc_hashtable(int size, int *vmalloced) | ||
1401 | { | ||
1402 | struct list_head *hash; | ||
1403 | unsigned int i; | ||
1404 | |||
1405 | *vmalloced = 0; | ||
1406 | hash = (void*)__get_free_pages(GFP_KERNEL, | ||
1407 | get_order(sizeof(struct list_head) | ||
1408 | * size)); | ||
1409 | if (!hash) { | ||
1410 | *vmalloced = 1; | ||
1411 | printk(KERN_WARNING "nf_conntrack: falling back to vmalloc.\n"); | ||
1412 | hash = vmalloc(sizeof(struct list_head) * size); | ||
1413 | } | ||
1414 | |||
1415 | if (hash) | ||
1416 | for (i = 0; i < size; i++) | ||
1417 | INIT_LIST_HEAD(&hash[i]); | ||
1418 | |||
1419 | return hash; | ||
1420 | } | ||
1421 | |||
1422 | int set_hashsize(const char *val, struct kernel_param *kp) | ||
1423 | { | ||
1424 | int i, bucket, hashsize, vmalloced; | ||
1425 | int old_vmalloced, old_size; | ||
1426 | int rnd; | ||
1427 | struct list_head *hash, *old_hash; | ||
1428 | struct nf_conntrack_tuple_hash *h; | ||
1429 | |||
1430 | /* On boot, we can set this without any fancy locking. */ | ||
1431 | if (!nf_conntrack_htable_size) | ||
1432 | return param_set_uint(val, kp); | ||
1433 | |||
1434 | hashsize = simple_strtol(val, NULL, 0); | ||
1435 | if (!hashsize) | ||
1436 | return -EINVAL; | ||
1437 | |||
1438 | hash = alloc_hashtable(hashsize, &vmalloced); | ||
1439 | if (!hash) | ||
1440 | return -ENOMEM; | ||
1441 | |||
1442 | /* We have to rehahs for the new table anyway, so we also can | ||
1443 | * use a newrandom seed */ | ||
1444 | get_random_bytes(&rnd, 4); | ||
1445 | |||
1446 | write_lock_bh(&nf_conntrack_lock); | ||
1447 | for (i = 0; i < nf_conntrack_htable_size; i++) { | ||
1448 | while (!list_empty(&nf_conntrack_hash[i])) { | ||
1449 | h = list_entry(nf_conntrack_hash[i].next, | ||
1450 | struct nf_conntrack_tuple_hash, list); | ||
1451 | list_del(&h->list); | ||
1452 | bucket = __hash_conntrack(&h->tuple, hashsize, rnd); | ||
1453 | list_add_tail(&h->list, &hash[bucket]); | ||
1454 | } | ||
1455 | } | ||
1456 | old_size = nf_conntrack_htable_size; | ||
1457 | old_vmalloced = nf_conntrack_vmalloc; | ||
1458 | old_hash = nf_conntrack_hash; | ||
1459 | |||
1460 | nf_conntrack_htable_size = hashsize; | ||
1461 | nf_conntrack_vmalloc = vmalloced; | ||
1462 | nf_conntrack_hash = hash; | ||
1463 | nf_conntrack_hash_rnd = rnd; | ||
1464 | write_unlock_bh(&nf_conntrack_lock); | ||
1465 | |||
1466 | free_conntrack_hash(old_hash, old_vmalloced, old_size); | ||
1467 | return 0; | ||
1468 | } | ||
1469 | |||
1470 | module_param_call(hashsize, set_hashsize, param_get_uint, | ||
1471 | &nf_conntrack_htable_size, 0600); | ||
1472 | |||
1473 | int __init nf_conntrack_init(void) | ||
1474 | { | ||
1475 | unsigned int i; | ||
1476 | int ret; | ||
1477 | |||
1478 | /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB | ||
1479 | * machine has 256 buckets. >= 1GB machines have 8192 buckets. */ | ||
1480 | if (!nf_conntrack_htable_size) { | ||
1481 | nf_conntrack_htable_size | ||
1482 | = (((num_physpages << PAGE_SHIFT) / 16384) | ||
1483 | / sizeof(struct list_head)); | ||
1484 | if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE)) | ||
1485 | nf_conntrack_htable_size = 8192; | ||
1486 | if (nf_conntrack_htable_size < 16) | ||
1487 | nf_conntrack_htable_size = 16; | ||
1488 | } | ||
1489 | nf_conntrack_max = 8 * nf_conntrack_htable_size; | ||
1490 | |||
1491 | printk("nf_conntrack version %s (%u buckets, %d max)\n", | ||
1492 | NF_CONNTRACK_VERSION, nf_conntrack_htable_size, | ||
1493 | nf_conntrack_max); | ||
1494 | |||
1495 | nf_conntrack_hash = alloc_hashtable(nf_conntrack_htable_size, | ||
1496 | &nf_conntrack_vmalloc); | ||
1497 | if (!nf_conntrack_hash) { | ||
1498 | printk(KERN_ERR "Unable to create nf_conntrack_hash\n"); | ||
1499 | goto err_out; | ||
1500 | } | ||
1501 | |||
1502 | ret = nf_conntrack_register_cache(NF_CT_F_BASIC, "nf_conntrack:basic", | ||
1503 | sizeof(struct nf_conn), NULL); | ||
1504 | if (ret < 0) { | ||
1505 | printk(KERN_ERR "Unable to create nf_conn slab cache\n"); | ||
1506 | goto err_free_hash; | ||
1507 | } | ||
1508 | |||
1509 | nf_conntrack_expect_cachep = kmem_cache_create("nf_conntrack_expect", | ||
1510 | sizeof(struct nf_conntrack_expect), | ||
1511 | 0, 0, NULL, NULL); | ||
1512 | if (!nf_conntrack_expect_cachep) { | ||
1513 | printk(KERN_ERR "Unable to create nf_expect slab cache\n"); | ||
1514 | goto err_free_conntrack_slab; | ||
1515 | } | ||
1516 | |||
1517 | /* Don't NEED lock here, but good form anyway. */ | ||
1518 | write_lock_bh(&nf_conntrack_lock); | ||
1519 | for (i = 0; i < PF_MAX; i++) | ||
1520 | nf_ct_l3protos[i] = &nf_conntrack_generic_l3proto; | ||
1521 | write_unlock_bh(&nf_conntrack_lock); | ||
1522 | |||
1523 | /* Set up fake conntrack: | ||
1524 | - to never be deleted, not in any hashes */ | ||
1525 | atomic_set(&nf_conntrack_untracked.ct_general.use, 1); | ||
1526 | /* - and look it like as a confirmed connection */ | ||
1527 | set_bit(IPS_CONFIRMED_BIT, &nf_conntrack_untracked.status); | ||
1528 | |||
1529 | return ret; | ||
1530 | |||
1531 | err_free_conntrack_slab: | ||
1532 | nf_conntrack_unregister_cache(NF_CT_F_BASIC); | ||
1533 | err_free_hash: | ||
1534 | free_conntrack_hash(nf_conntrack_hash, nf_conntrack_vmalloc, | ||
1535 | nf_conntrack_htable_size); | ||
1536 | err_out: | ||
1537 | return -ENOMEM; | ||
1538 | } | ||
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c new file mode 100644 index 000000000000..65080e269f27 --- /dev/null +++ b/net/netfilter/nf_conntrack_ftp.c | |||
@@ -0,0 +1,698 @@ | |||
1 | /* FTP extension for connection tracking. */ | ||
2 | |||
3 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
4 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
5 | * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
12 | * - enable working with Layer 3 protocol independent connection tracking. | ||
13 | * - track EPRT and EPSV commands with IPv6 address. | ||
14 | * | ||
15 | * Derived from net/ipv4/netfilter/ip_conntrack_ftp.c | ||
16 | */ | ||
17 | |||
18 | #include <linux/config.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/moduleparam.h> | ||
21 | #include <linux/netfilter.h> | ||
22 | #include <linux/ip.h> | ||
23 | #include <linux/ipv6.h> | ||
24 | #include <linux/ctype.h> | ||
25 | #include <net/checksum.h> | ||
26 | #include <net/tcp.h> | ||
27 | |||
28 | #include <net/netfilter/nf_conntrack.h> | ||
29 | #include <net/netfilter/nf_conntrack_helper.h> | ||
30 | #include <linux/netfilter/nf_conntrack_ftp.h> | ||
31 | |||
32 | MODULE_LICENSE("GPL"); | ||
33 | MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>"); | ||
34 | MODULE_DESCRIPTION("ftp connection tracking helper"); | ||
35 | |||
36 | /* This is slow, but it's simple. --RR */ | ||
37 | static char *ftp_buffer; | ||
38 | |||
39 | static DEFINE_SPINLOCK(nf_ftp_lock); | ||
40 | |||
41 | #define MAX_PORTS 8 | ||
42 | static u_int16_t ports[MAX_PORTS]; | ||
43 | static unsigned int ports_c; | ||
44 | module_param_array(ports, ushort, &ports_c, 0400); | ||
45 | |||
46 | static int loose; | ||
47 | module_param(loose, int, 0600); | ||
48 | |||
49 | unsigned int (*nf_nat_ftp_hook)(struct sk_buff **pskb, | ||
50 | enum ip_conntrack_info ctinfo, | ||
51 | enum ip_ct_ftp_type type, | ||
52 | unsigned int matchoff, | ||
53 | unsigned int matchlen, | ||
54 | struct nf_conntrack_expect *exp, | ||
55 | u32 *seq); | ||
56 | EXPORT_SYMBOL_GPL(nf_nat_ftp_hook); | ||
57 | |||
58 | #if 0 | ||
59 | #define DEBUGP printk | ||
60 | #else | ||
61 | #define DEBUGP(format, args...) | ||
62 | #endif | ||
63 | |||
64 | static int try_rfc959(const char *, size_t, struct nf_conntrack_man *, char); | ||
65 | static int try_eprt(const char *, size_t, struct nf_conntrack_man *, char); | ||
66 | static int try_epsv_response(const char *, size_t, struct nf_conntrack_man *, | ||
67 | char); | ||
68 | |||
69 | static struct ftp_search { | ||
70 | enum ip_conntrack_dir dir; | ||
71 | const char *pattern; | ||
72 | size_t plen; | ||
73 | char skip; | ||
74 | char term; | ||
75 | enum ip_ct_ftp_type ftptype; | ||
76 | int (*getnum)(const char *, size_t, struct nf_conntrack_man *, char); | ||
77 | } search[] = { | ||
78 | { | ||
79 | IP_CT_DIR_ORIGINAL, | ||
80 | "PORT", sizeof("PORT") - 1, ' ', '\r', | ||
81 | IP_CT_FTP_PORT, | ||
82 | try_rfc959, | ||
83 | }, | ||
84 | { | ||
85 | IP_CT_DIR_REPLY, | ||
86 | "227 ", sizeof("227 ") - 1, '(', ')', | ||
87 | IP_CT_FTP_PASV, | ||
88 | try_rfc959, | ||
89 | }, | ||
90 | { | ||
91 | IP_CT_DIR_ORIGINAL, | ||
92 | "EPRT", sizeof("EPRT") - 1, ' ', '\r', | ||
93 | IP_CT_FTP_EPRT, | ||
94 | try_eprt, | ||
95 | }, | ||
96 | { | ||
97 | IP_CT_DIR_REPLY, | ||
98 | "229 ", sizeof("229 ") - 1, '(', ')', | ||
99 | IP_CT_FTP_EPSV, | ||
100 | try_epsv_response, | ||
101 | }, | ||
102 | }; | ||
103 | |||
104 | /* This code is based on inet_pton() in glibc-2.2.4 */ | ||
105 | static int | ||
106 | get_ipv6_addr(const char *src, size_t dlen, struct in6_addr *dst, u_int8_t term) | ||
107 | { | ||
108 | static const char xdigits[] = "0123456789abcdef"; | ||
109 | u_int8_t tmp[16], *tp, *endp, *colonp; | ||
110 | int ch, saw_xdigit; | ||
111 | u_int32_t val; | ||
112 | size_t clen = 0; | ||
113 | |||
114 | tp = memset(tmp, '\0', sizeof(tmp)); | ||
115 | endp = tp + sizeof(tmp); | ||
116 | colonp = NULL; | ||
117 | |||
118 | /* Leading :: requires some special handling. */ | ||
119 | if (*src == ':'){ | ||
120 | if (*++src != ':') { | ||
121 | DEBUGP("invalid \":\" at the head of addr\n"); | ||
122 | return 0; | ||
123 | } | ||
124 | clen++; | ||
125 | } | ||
126 | |||
127 | saw_xdigit = 0; | ||
128 | val = 0; | ||
129 | while ((clen < dlen) && (*src != term)) { | ||
130 | const char *pch; | ||
131 | |||
132 | ch = tolower(*src++); | ||
133 | clen++; | ||
134 | |||
135 | pch = strchr(xdigits, ch); | ||
136 | if (pch != NULL) { | ||
137 | val <<= 4; | ||
138 | val |= (pch - xdigits); | ||
139 | if (val > 0xffff) | ||
140 | return 0; | ||
141 | |||
142 | saw_xdigit = 1; | ||
143 | continue; | ||
144 | } | ||
145 | if (ch != ':') { | ||
146 | DEBUGP("get_ipv6_addr: invalid char. \'%c\'\n", ch); | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | if (!saw_xdigit) { | ||
151 | if (colonp) { | ||
152 | DEBUGP("invalid location of \"::\".\n"); | ||
153 | return 0; | ||
154 | } | ||
155 | colonp = tp; | ||
156 | continue; | ||
157 | } else if (*src == term) { | ||
158 | DEBUGP("trancated IPv6 addr\n"); | ||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | if (tp + 2 > endp) | ||
163 | return 0; | ||
164 | *tp++ = (u_int8_t) (val >> 8) & 0xff; | ||
165 | *tp++ = (u_int8_t) val & 0xff; | ||
166 | |||
167 | saw_xdigit = 0; | ||
168 | val = 0; | ||
169 | continue; | ||
170 | } | ||
171 | if (saw_xdigit) { | ||
172 | if (tp + 2 > endp) | ||
173 | return 0; | ||
174 | *tp++ = (u_int8_t) (val >> 8) & 0xff; | ||
175 | *tp++ = (u_int8_t) val & 0xff; | ||
176 | } | ||
177 | if (colonp != NULL) { | ||
178 | /* | ||
179 | * Since some memmove()'s erroneously fail to handle | ||
180 | * overlapping regions, we'll do the shift by hand. | ||
181 | */ | ||
182 | const int n = tp - colonp; | ||
183 | int i; | ||
184 | |||
185 | if (tp == endp) | ||
186 | return 0; | ||
187 | |||
188 | for (i = 1; i <= n; i++) { | ||
189 | endp[- i] = colonp[n - i]; | ||
190 | colonp[n - i] = 0; | ||
191 | } | ||
192 | tp = endp; | ||
193 | } | ||
194 | if (tp != endp || (*src != term)) | ||
195 | return 0; | ||
196 | |||
197 | memcpy(dst->s6_addr, tmp, sizeof(dst->s6_addr)); | ||
198 | return clen; | ||
199 | } | ||
200 | |||
201 | static int try_number(const char *data, size_t dlen, u_int32_t array[], | ||
202 | int array_size, char sep, char term) | ||
203 | { | ||
204 | u_int32_t i, len; | ||
205 | |||
206 | memset(array, 0, sizeof(array[0])*array_size); | ||
207 | |||
208 | /* Keep data pointing at next char. */ | ||
209 | for (i = 0, len = 0; len < dlen && i < array_size; len++, data++) { | ||
210 | if (*data >= '0' && *data <= '9') { | ||
211 | array[i] = array[i]*10 + *data - '0'; | ||
212 | } | ||
213 | else if (*data == sep) | ||
214 | i++; | ||
215 | else { | ||
216 | /* Unexpected character; true if it's the | ||
217 | terminator and we're finished. */ | ||
218 | if (*data == term && i == array_size - 1) | ||
219 | return len; | ||
220 | |||
221 | DEBUGP("Char %u (got %u nums) `%u' unexpected\n", | ||
222 | len, i, *data); | ||
223 | return 0; | ||
224 | } | ||
225 | } | ||
226 | DEBUGP("Failed to fill %u numbers separated by %c\n", array_size, sep); | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | /* Returns 0, or length of numbers: 192,168,1,1,5,6 */ | ||
232 | static int try_rfc959(const char *data, size_t dlen, | ||
233 | struct nf_conntrack_man *cmd, char term) | ||
234 | { | ||
235 | int length; | ||
236 | u_int32_t array[6]; | ||
237 | |||
238 | length = try_number(data, dlen, array, 6, ',', term); | ||
239 | if (length == 0) | ||
240 | return 0; | ||
241 | |||
242 | cmd->u3.ip = htonl((array[0] << 24) | (array[1] << 16) | | ||
243 | (array[2] << 8) | array[3]); | ||
244 | cmd->u.tcp.port = htons((array[4] << 8) | array[5]); | ||
245 | return length; | ||
246 | } | ||
247 | |||
248 | /* Grab port: number up to delimiter */ | ||
249 | static int get_port(const char *data, int start, size_t dlen, char delim, | ||
250 | u_int16_t *port) | ||
251 | { | ||
252 | u_int16_t tmp_port = 0; | ||
253 | int i; | ||
254 | |||
255 | for (i = start; i < dlen; i++) { | ||
256 | /* Finished? */ | ||
257 | if (data[i] == delim) { | ||
258 | if (tmp_port == 0) | ||
259 | break; | ||
260 | *port = htons(tmp_port); | ||
261 | DEBUGP("get_port: return %d\n", tmp_port); | ||
262 | return i + 1; | ||
263 | } | ||
264 | else if (data[i] >= '0' && data[i] <= '9') | ||
265 | tmp_port = tmp_port*10 + data[i] - '0'; | ||
266 | else { /* Some other crap */ | ||
267 | DEBUGP("get_port: invalid char.\n"); | ||
268 | break; | ||
269 | } | ||
270 | } | ||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | /* Returns 0, or length of numbers: |1|132.235.1.2|6275| or |2|3ffe::1|6275| */ | ||
275 | static int try_eprt(const char *data, size_t dlen, struct nf_conntrack_man *cmd, | ||
276 | char term) | ||
277 | { | ||
278 | char delim; | ||
279 | int length; | ||
280 | |||
281 | /* First character is delimiter, then "1" for IPv4 or "2" for IPv6, | ||
282 | then delimiter again. */ | ||
283 | if (dlen <= 3) { | ||
284 | DEBUGP("EPRT: too short\n"); | ||
285 | return 0; | ||
286 | } | ||
287 | delim = data[0]; | ||
288 | if (isdigit(delim) || delim < 33 || delim > 126 || data[2] != delim) { | ||
289 | DEBUGP("try_eprt: invalid delimitter.\n"); | ||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | if ((cmd->l3num == PF_INET && data[1] != '1') || | ||
294 | (cmd->l3num == PF_INET6 && data[1] != '2')) { | ||
295 | DEBUGP("EPRT: invalid protocol number.\n"); | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | DEBUGP("EPRT: Got %c%c%c\n", delim, data[1], delim); | ||
300 | |||
301 | if (data[1] == '1') { | ||
302 | u_int32_t array[4]; | ||
303 | |||
304 | /* Now we have IP address. */ | ||
305 | length = try_number(data + 3, dlen - 3, array, 4, '.', delim); | ||
306 | if (length != 0) | ||
307 | cmd->u3.ip = htonl((array[0] << 24) | (array[1] << 16) | ||
308 | | (array[2] << 8) | array[3]); | ||
309 | } else { | ||
310 | /* Now we have IPv6 address. */ | ||
311 | length = get_ipv6_addr(data + 3, dlen - 3, | ||
312 | (struct in6_addr *)cmd->u3.ip6, delim); | ||
313 | } | ||
314 | |||
315 | if (length == 0) | ||
316 | return 0; | ||
317 | DEBUGP("EPRT: Got IP address!\n"); | ||
318 | /* Start offset includes initial "|1|", and trailing delimiter */ | ||
319 | return get_port(data, 3 + length + 1, dlen, delim, &cmd->u.tcp.port); | ||
320 | } | ||
321 | |||
322 | /* Returns 0, or length of numbers: |||6446| */ | ||
323 | static int try_epsv_response(const char *data, size_t dlen, | ||
324 | struct nf_conntrack_man *cmd, char term) | ||
325 | { | ||
326 | char delim; | ||
327 | |||
328 | /* Three delimiters. */ | ||
329 | if (dlen <= 3) return 0; | ||
330 | delim = data[0]; | ||
331 | if (isdigit(delim) || delim < 33 || delim > 126 | ||
332 | || data[1] != delim || data[2] != delim) | ||
333 | return 0; | ||
334 | |||
335 | return get_port(data, 3, dlen, delim, &cmd->u.tcp.port); | ||
336 | } | ||
337 | |||
338 | /* Return 1 for match, 0 for accept, -1 for partial. */ | ||
339 | static int find_pattern(const char *data, size_t dlen, | ||
340 | const char *pattern, size_t plen, | ||
341 | char skip, char term, | ||
342 | unsigned int *numoff, | ||
343 | unsigned int *numlen, | ||
344 | struct nf_conntrack_man *cmd, | ||
345 | int (*getnum)(const char *, size_t, | ||
346 | struct nf_conntrack_man *, char)) | ||
347 | { | ||
348 | size_t i; | ||
349 | |||
350 | DEBUGP("find_pattern `%s': dlen = %u\n", pattern, dlen); | ||
351 | if (dlen == 0) | ||
352 | return 0; | ||
353 | |||
354 | if (dlen <= plen) { | ||
355 | /* Short packet: try for partial? */ | ||
356 | if (strnicmp(data, pattern, dlen) == 0) | ||
357 | return -1; | ||
358 | else return 0; | ||
359 | } | ||
360 | |||
361 | if (strnicmp(data, pattern, plen) != 0) { | ||
362 | #if 0 | ||
363 | size_t i; | ||
364 | |||
365 | DEBUGP("ftp: string mismatch\n"); | ||
366 | for (i = 0; i < plen; i++) { | ||
367 | DEBUGP("ftp:char %u `%c'(%u) vs `%c'(%u)\n", | ||
368 | i, data[i], data[i], | ||
369 | pattern[i], pattern[i]); | ||
370 | } | ||
371 | #endif | ||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | DEBUGP("Pattern matches!\n"); | ||
376 | /* Now we've found the constant string, try to skip | ||
377 | to the 'skip' character */ | ||
378 | for (i = plen; data[i] != skip; i++) | ||
379 | if (i == dlen - 1) return -1; | ||
380 | |||
381 | /* Skip over the last character */ | ||
382 | i++; | ||
383 | |||
384 | DEBUGP("Skipped up to `%c'!\n", skip); | ||
385 | |||
386 | *numoff = i; | ||
387 | *numlen = getnum(data + i, dlen - i, cmd, term); | ||
388 | if (!*numlen) | ||
389 | return -1; | ||
390 | |||
391 | DEBUGP("Match succeeded!\n"); | ||
392 | return 1; | ||
393 | } | ||
394 | |||
395 | /* Look up to see if we're just after a \n. */ | ||
396 | static int find_nl_seq(u32 seq, const struct ip_ct_ftp_master *info, int dir) | ||
397 | { | ||
398 | unsigned int i; | ||
399 | |||
400 | for (i = 0; i < info->seq_aft_nl_num[dir]; i++) | ||
401 | if (info->seq_aft_nl[dir][i] == seq) | ||
402 | return 1; | ||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | /* We don't update if it's older than what we have. */ | ||
407 | static void update_nl_seq(u32 nl_seq, struct ip_ct_ftp_master *info, int dir, | ||
408 | struct sk_buff *skb) | ||
409 | { | ||
410 | unsigned int i, oldest = NUM_SEQ_TO_REMEMBER; | ||
411 | |||
412 | /* Look for oldest: if we find exact match, we're done. */ | ||
413 | for (i = 0; i < info->seq_aft_nl_num[dir]; i++) { | ||
414 | if (info->seq_aft_nl[dir][i] == nl_seq) | ||
415 | return; | ||
416 | |||
417 | if (oldest == info->seq_aft_nl_num[dir] | ||
418 | || before(info->seq_aft_nl[dir][i], oldest)) | ||
419 | oldest = i; | ||
420 | } | ||
421 | |||
422 | if (info->seq_aft_nl_num[dir] < NUM_SEQ_TO_REMEMBER) { | ||
423 | info->seq_aft_nl[dir][info->seq_aft_nl_num[dir]++] = nl_seq; | ||
424 | nf_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, skb); | ||
425 | } else if (oldest != NUM_SEQ_TO_REMEMBER) { | ||
426 | info->seq_aft_nl[dir][oldest] = nl_seq; | ||
427 | nf_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, skb); | ||
428 | } | ||
429 | } | ||
430 | |||
431 | static int help(struct sk_buff **pskb, | ||
432 | unsigned int protoff, | ||
433 | struct nf_conn *ct, | ||
434 | enum ip_conntrack_info ctinfo) | ||
435 | { | ||
436 | unsigned int dataoff, datalen; | ||
437 | struct tcphdr _tcph, *th; | ||
438 | char *fb_ptr; | ||
439 | int ret; | ||
440 | u32 seq; | ||
441 | int dir = CTINFO2DIR(ctinfo); | ||
442 | unsigned int matchlen, matchoff; | ||
443 | struct ip_ct_ftp_master *ct_ftp_info = &ct->help->ct_ftp_info; | ||
444 | struct nf_conntrack_expect *exp; | ||
445 | struct nf_conntrack_man cmd = {}; | ||
446 | |||
447 | unsigned int i; | ||
448 | int found = 0, ends_in_nl; | ||
449 | |||
450 | /* Until there's been traffic both ways, don't look in packets. */ | ||
451 | if (ctinfo != IP_CT_ESTABLISHED | ||
452 | && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) { | ||
453 | DEBUGP("ftp: Conntrackinfo = %u\n", ctinfo); | ||
454 | return NF_ACCEPT; | ||
455 | } | ||
456 | |||
457 | th = skb_header_pointer(*pskb, protoff, sizeof(_tcph), &_tcph); | ||
458 | if (th == NULL) | ||
459 | return NF_ACCEPT; | ||
460 | |||
461 | dataoff = protoff + th->doff * 4; | ||
462 | /* No data? */ | ||
463 | if (dataoff >= (*pskb)->len) { | ||
464 | DEBUGP("ftp: dataoff(%u) >= skblen(%u)\n", dataoff, | ||
465 | (*pskb)->len); | ||
466 | return NF_ACCEPT; | ||
467 | } | ||
468 | datalen = (*pskb)->len - dataoff; | ||
469 | |||
470 | spin_lock_bh(&nf_ftp_lock); | ||
471 | fb_ptr = skb_header_pointer(*pskb, dataoff, datalen, ftp_buffer); | ||
472 | BUG_ON(fb_ptr == NULL); | ||
473 | |||
474 | ends_in_nl = (fb_ptr[datalen - 1] == '\n'); | ||
475 | seq = ntohl(th->seq) + datalen; | ||
476 | |||
477 | /* Look up to see if we're just after a \n. */ | ||
478 | if (!find_nl_seq(ntohl(th->seq), ct_ftp_info, dir)) { | ||
479 | /* Now if this ends in \n, update ftp info. */ | ||
480 | DEBUGP("nf_conntrack_ftp_help: wrong seq pos %s(%u) or %s(%u)\n", | ||
481 | ct_ftp_info->seq_aft_nl_num[dir] > 0 ? "" : "(UNSET)", | ||
482 | ct_ftp_info->seq_aft_nl[dir][0], | ||
483 | ct_ftp_info->seq_aft_nl_num[dir] > 1 ? "" : "(UNSET)", | ||
484 | ct_ftp_info->seq_aft_nl[dir][1]); | ||
485 | ret = NF_ACCEPT; | ||
486 | goto out_update_nl; | ||
487 | } | ||
488 | |||
489 | /* Initialize IP/IPv6 addr to expected address (it's not mentioned | ||
490 | in EPSV responses) */ | ||
491 | cmd.l3num = ct->tuplehash[dir].tuple.src.l3num; | ||
492 | memcpy(cmd.u3.all, &ct->tuplehash[dir].tuple.src.u3.all, | ||
493 | sizeof(cmd.u3.all)); | ||
494 | |||
495 | for (i = 0; i < ARRAY_SIZE(search); i++) { | ||
496 | if (search[i].dir != dir) continue; | ||
497 | |||
498 | found = find_pattern(fb_ptr, datalen, | ||
499 | search[i].pattern, | ||
500 | search[i].plen, | ||
501 | search[i].skip, | ||
502 | search[i].term, | ||
503 | &matchoff, &matchlen, | ||
504 | &cmd, | ||
505 | search[i].getnum); | ||
506 | if (found) break; | ||
507 | } | ||
508 | if (found == -1) { | ||
509 | /* We don't usually drop packets. After all, this is | ||
510 | connection tracking, not packet filtering. | ||
511 | However, it is necessary for accurate tracking in | ||
512 | this case. */ | ||
513 | if (net_ratelimit()) | ||
514 | printk("conntrack_ftp: partial %s %u+%u\n", | ||
515 | search[i].pattern, | ||
516 | ntohl(th->seq), datalen); | ||
517 | ret = NF_DROP; | ||
518 | goto out; | ||
519 | } else if (found == 0) { /* No match */ | ||
520 | ret = NF_ACCEPT; | ||
521 | goto out_update_nl; | ||
522 | } | ||
523 | |||
524 | DEBUGP("conntrack_ftp: match `%.*s' (%u bytes at %u)\n", | ||
525 | (int)matchlen, fb_ptr + matchoff, | ||
526 | matchlen, ntohl(th->seq) + matchoff); | ||
527 | |||
528 | exp = nf_conntrack_expect_alloc(ct); | ||
529 | if (exp == NULL) { | ||
530 | ret = NF_DROP; | ||
531 | goto out; | ||
532 | } | ||
533 | |||
534 | /* We refer to the reverse direction ("!dir") tuples here, | ||
535 | * because we're expecting something in the other direction. | ||
536 | * Doesn't matter unless NAT is happening. */ | ||
537 | exp->tuple.dst.u3 = ct->tuplehash[!dir].tuple.dst.u3; | ||
538 | |||
539 | /* Update the ftp info */ | ||
540 | if ((cmd.l3num == ct->tuplehash[dir].tuple.src.l3num) && | ||
541 | memcmp(&cmd.u3.all, &ct->tuplehash[dir].tuple.src.u3.all, | ||
542 | sizeof(cmd.u3.all))) { | ||
543 | /* Enrico Scholz's passive FTP to partially RNAT'd ftp | ||
544 | server: it really wants us to connect to a | ||
545 | different IP address. Simply don't record it for | ||
546 | NAT. */ | ||
547 | if (cmd.l3num == PF_INET) { | ||
548 | DEBUGP("conntrack_ftp: NOT RECORDING: %u,%u,%u,%u != %u.%u.%u.%u\n", | ||
549 | NIPQUAD(cmd.u3.ip), | ||
550 | NIPQUAD(ct->tuplehash[dir].tuple.src.u3.ip)); | ||
551 | } else { | ||
552 | DEBUGP("conntrack_ftp: NOT RECORDING: %x:%x:%x:%x:%x:%x:%x:%x != %x:%x:%x:%x:%x:%x:%x:%x\n", | ||
553 | NIP6(*((struct in6_addr *)cmd.u3.ip6)), | ||
554 | NIP6(*((struct in6_addr *)ct->tuplehash[dir] | ||
555 | .tuple.src.u3.ip6))); | ||
556 | } | ||
557 | |||
558 | /* Thanks to Cristiano Lincoln Mattos | ||
559 | <lincoln@cesar.org.br> for reporting this potential | ||
560 | problem (DMZ machines opening holes to internal | ||
561 | networks, or the packet filter itself). */ | ||
562 | if (!loose) { | ||
563 | ret = NF_ACCEPT; | ||
564 | goto out_put_expect; | ||
565 | } | ||
566 | memcpy(&exp->tuple.dst.u3, &cmd.u3.all, | ||
567 | sizeof(exp->tuple.dst.u3)); | ||
568 | } | ||
569 | |||
570 | exp->tuple.src.u3 = ct->tuplehash[!dir].tuple.src.u3; | ||
571 | exp->tuple.src.l3num = cmd.l3num; | ||
572 | exp->tuple.src.u.tcp.port = 0; | ||
573 | exp->tuple.dst.u.tcp.port = cmd.u.tcp.port; | ||
574 | exp->tuple.dst.protonum = IPPROTO_TCP; | ||
575 | |||
576 | exp->mask = (struct nf_conntrack_tuple) | ||
577 | { .src = { .l3num = 0xFFFF, | ||
578 | .u = { .tcp = { 0 }}, | ||
579 | }, | ||
580 | .dst = { .protonum = 0xFF, | ||
581 | .u = { .tcp = { 0xFFFF }}, | ||
582 | }, | ||
583 | }; | ||
584 | if (cmd.l3num == PF_INET) { | ||
585 | exp->mask.src.u3.ip = 0xFFFFFFFF; | ||
586 | exp->mask.dst.u3.ip = 0xFFFFFFFF; | ||
587 | } else { | ||
588 | memset(exp->mask.src.u3.ip6, 0xFF, | ||
589 | sizeof(exp->mask.src.u3.ip6)); | ||
590 | memset(exp->mask.dst.u3.ip6, 0xFF, | ||
591 | sizeof(exp->mask.src.u3.ip6)); | ||
592 | } | ||
593 | |||
594 | exp->expectfn = NULL; | ||
595 | exp->flags = 0; | ||
596 | |||
597 | /* Now, NAT might want to mangle the packet, and register the | ||
598 | * (possibly changed) expectation itself. */ | ||
599 | if (nf_nat_ftp_hook) | ||
600 | ret = nf_nat_ftp_hook(pskb, ctinfo, search[i].ftptype, | ||
601 | matchoff, matchlen, exp, &seq); | ||
602 | else { | ||
603 | /* Can't expect this? Best to drop packet now. */ | ||
604 | if (nf_conntrack_expect_related(exp) != 0) | ||
605 | ret = NF_DROP; | ||
606 | else | ||
607 | ret = NF_ACCEPT; | ||
608 | } | ||
609 | |||
610 | out_put_expect: | ||
611 | nf_conntrack_expect_put(exp); | ||
612 | |||
613 | out_update_nl: | ||
614 | /* Now if this ends in \n, update ftp info. Seq may have been | ||
615 | * adjusted by NAT code. */ | ||
616 | if (ends_in_nl) | ||
617 | update_nl_seq(seq, ct_ftp_info, dir, *pskb); | ||
618 | out: | ||
619 | spin_unlock_bh(&nf_ftp_lock); | ||
620 | return ret; | ||
621 | } | ||
622 | |||
623 | static struct nf_conntrack_helper ftp[MAX_PORTS][2]; | ||
624 | static char ftp_names[MAX_PORTS][2][sizeof("ftp-65535")]; | ||
625 | |||
626 | /* don't make this __exit, since it's called from __init ! */ | ||
627 | static void fini(void) | ||
628 | { | ||
629 | int i, j; | ||
630 | for (i = 0; i < ports_c; i++) { | ||
631 | for (j = 0; j < 2; j++) { | ||
632 | if (ftp[i][j].me == NULL) | ||
633 | continue; | ||
634 | |||
635 | DEBUGP("nf_ct_ftp: unregistering helper for pf: %d " | ||
636 | "port: %d\n", | ||
637 | ftp[i][j].tuple.src.l3num, ports[i]); | ||
638 | nf_conntrack_helper_unregister(&ftp[i][j]); | ||
639 | } | ||
640 | } | ||
641 | |||
642 | kfree(ftp_buffer); | ||
643 | } | ||
644 | |||
645 | static int __init init(void) | ||
646 | { | ||
647 | int i, j = -1, ret = 0; | ||
648 | char *tmpname; | ||
649 | |||
650 | ftp_buffer = kmalloc(65536, GFP_KERNEL); | ||
651 | if (!ftp_buffer) | ||
652 | return -ENOMEM; | ||
653 | |||
654 | if (ports_c == 0) | ||
655 | ports[ports_c++] = FTP_PORT; | ||
656 | |||
657 | /* FIXME should be configurable whether IPv4 and IPv6 FTP connections | ||
658 | are tracked or not - YK */ | ||
659 | for (i = 0; i < ports_c; i++) { | ||
660 | memset(&ftp[i], 0, sizeof(struct nf_conntrack_helper)); | ||
661 | |||
662 | ftp[i][0].tuple.src.l3num = PF_INET; | ||
663 | ftp[i][1].tuple.src.l3num = PF_INET6; | ||
664 | for (j = 0; j < 2; j++) { | ||
665 | ftp[i][j].tuple.src.u.tcp.port = htons(ports[i]); | ||
666 | ftp[i][j].tuple.dst.protonum = IPPROTO_TCP; | ||
667 | ftp[i][j].mask.src.u.tcp.port = 0xFFFF; | ||
668 | ftp[i][j].mask.dst.protonum = 0xFF; | ||
669 | ftp[i][j].max_expected = 1; | ||
670 | ftp[i][j].timeout = 5 * 60; /* 5 Minutes */ | ||
671 | ftp[i][j].me = THIS_MODULE; | ||
672 | ftp[i][j].help = help; | ||
673 | tmpname = &ftp_names[i][j][0]; | ||
674 | if (ports[i] == FTP_PORT) | ||
675 | sprintf(tmpname, "ftp"); | ||
676 | else | ||
677 | sprintf(tmpname, "ftp-%d", ports[i]); | ||
678 | ftp[i][j].name = tmpname; | ||
679 | |||
680 | DEBUGP("nf_ct_ftp: registering helper for pf: %d " | ||
681 | "port: %d\n", | ||
682 | ftp[i][j].tuple.src.l3num, ports[i]); | ||
683 | ret = nf_conntrack_helper_register(&ftp[i][j]); | ||
684 | if (ret) { | ||
685 | printk("nf_ct_ftp: failed to register helper " | ||
686 | " for pf: %d port: %d\n", | ||
687 | ftp[i][j].tuple.src.l3num, ports[i]); | ||
688 | fini(); | ||
689 | return ret; | ||
690 | } | ||
691 | } | ||
692 | } | ||
693 | |||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | module_init(init); | ||
698 | module_exit(fini); | ||
diff --git a/net/netfilter/nf_conntrack_l3proto_generic.c b/net/netfilter/nf_conntrack_l3proto_generic.c new file mode 100644 index 000000000000..7de4f06c63c5 --- /dev/null +++ b/net/netfilter/nf_conntrack_l3proto_generic.c | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org> | ||
3 | * | ||
4 | * Based largely upon the original ip_conntrack code which | ||
5 | * had the following copyright information: | ||
6 | * | ||
7 | * (C) 1999-2001 Paul `Rusty' Russell | ||
8 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * Author: | ||
15 | * Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
16 | */ | ||
17 | |||
18 | #include <linux/config.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/ip.h> | ||
21 | #include <linux/netfilter.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/skbuff.h> | ||
24 | #include <linux/icmp.h> | ||
25 | #include <linux/sysctl.h> | ||
26 | #include <net/ip.h> | ||
27 | |||
28 | #include <linux/netfilter_ipv4.h> | ||
29 | #include <net/netfilter/nf_conntrack.h> | ||
30 | #include <net/netfilter/nf_conntrack_protocol.h> | ||
31 | #include <net/netfilter/nf_conntrack_l3proto.h> | ||
32 | #include <net/netfilter/nf_conntrack_core.h> | ||
33 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> | ||
34 | |||
35 | #if 0 | ||
36 | #define DEBUGP printk | ||
37 | #else | ||
38 | #define DEBUGP(format, args...) | ||
39 | #endif | ||
40 | |||
41 | DECLARE_PER_CPU(struct nf_conntrack_stat, nf_conntrack_stat); | ||
42 | |||
43 | static int generic_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, | ||
44 | struct nf_conntrack_tuple *tuple) | ||
45 | { | ||
46 | memset(&tuple->src.u3, 0, sizeof(tuple->src.u3)); | ||
47 | memset(&tuple->dst.u3, 0, sizeof(tuple->dst.u3)); | ||
48 | |||
49 | return 1; | ||
50 | } | ||
51 | |||
52 | static int generic_invert_tuple(struct nf_conntrack_tuple *tuple, | ||
53 | const struct nf_conntrack_tuple *orig) | ||
54 | { | ||
55 | memset(&tuple->src.u3, 0, sizeof(tuple->src.u3)); | ||
56 | memset(&tuple->dst.u3, 0, sizeof(tuple->dst.u3)); | ||
57 | |||
58 | return 1; | ||
59 | } | ||
60 | |||
61 | static int generic_print_tuple(struct seq_file *s, | ||
62 | const struct nf_conntrack_tuple *tuple) | ||
63 | { | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static int generic_print_conntrack(struct seq_file *s, | ||
68 | const struct nf_conn *conntrack) | ||
69 | { | ||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static int | ||
74 | generic_prepare(struct sk_buff **pskb, unsigned int hooknum, | ||
75 | unsigned int *dataoff, u_int8_t *protonum) | ||
76 | { | ||
77 | /* Never track !!! */ | ||
78 | return -NF_ACCEPT; | ||
79 | } | ||
80 | |||
81 | |||
82 | static u_int32_t generic_get_features(const struct nf_conntrack_tuple *tuple) | ||
83 | |||
84 | { | ||
85 | return NF_CT_F_BASIC; | ||
86 | } | ||
87 | |||
88 | struct nf_conntrack_l3proto nf_conntrack_generic_l3proto = { | ||
89 | .l3proto = PF_UNSPEC, | ||
90 | .name = "unknown", | ||
91 | .pkt_to_tuple = generic_pkt_to_tuple, | ||
92 | .invert_tuple = generic_invert_tuple, | ||
93 | .print_tuple = generic_print_tuple, | ||
94 | .print_conntrack = generic_print_conntrack, | ||
95 | .prepare = generic_prepare, | ||
96 | .get_features = generic_get_features, | ||
97 | .me = THIS_MODULE, | ||
98 | }; | ||
diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c new file mode 100644 index 000000000000..36425f6c833f --- /dev/null +++ b/net/netfilter/nf_conntrack_proto_generic.c | |||
@@ -0,0 +1,85 @@ | |||
1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
9 | * - enable working with L3 protocol independent connection tracking. | ||
10 | * | ||
11 | * Derived from net/ipv4/netfilter/ip_conntrack_proto_generic.c | ||
12 | */ | ||
13 | |||
14 | #include <linux/types.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <linux/timer.h> | ||
17 | #include <linux/netfilter.h> | ||
18 | #include <net/netfilter/nf_conntrack_protocol.h> | ||
19 | |||
20 | unsigned long nf_ct_generic_timeout = 600*HZ; | ||
21 | |||
22 | static int generic_pkt_to_tuple(const struct sk_buff *skb, | ||
23 | unsigned int dataoff, | ||
24 | struct nf_conntrack_tuple *tuple) | ||
25 | { | ||
26 | tuple->src.u.all = 0; | ||
27 | tuple->dst.u.all = 0; | ||
28 | |||
29 | return 1; | ||
30 | } | ||
31 | |||
32 | static int generic_invert_tuple(struct nf_conntrack_tuple *tuple, | ||
33 | const struct nf_conntrack_tuple *orig) | ||
34 | { | ||
35 | tuple->src.u.all = 0; | ||
36 | tuple->dst.u.all = 0; | ||
37 | |||
38 | return 1; | ||
39 | } | ||
40 | |||
41 | /* Print out the per-protocol part of the tuple. */ | ||
42 | static int generic_print_tuple(struct seq_file *s, | ||
43 | const struct nf_conntrack_tuple *tuple) | ||
44 | { | ||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | /* Print out the private part of the conntrack. */ | ||
49 | static int generic_print_conntrack(struct seq_file *s, | ||
50 | const struct nf_conn *state) | ||
51 | { | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | /* Returns verdict for packet, or -1 for invalid. */ | ||
56 | static int packet(struct nf_conn *conntrack, | ||
57 | const struct sk_buff *skb, | ||
58 | unsigned int dataoff, | ||
59 | enum ip_conntrack_info ctinfo, | ||
60 | int pf, | ||
61 | unsigned int hooknum) | ||
62 | { | ||
63 | nf_ct_refresh_acct(conntrack, ctinfo, skb, nf_ct_generic_timeout); | ||
64 | return NF_ACCEPT; | ||
65 | } | ||
66 | |||
67 | /* Called when a new connection for this protocol found. */ | ||
68 | static int new(struct nf_conn *conntrack, const struct sk_buff *skb, | ||
69 | unsigned int dataoff) | ||
70 | { | ||
71 | return 1; | ||
72 | } | ||
73 | |||
74 | struct nf_conntrack_protocol nf_conntrack_generic_protocol = | ||
75 | { | ||
76 | .l3proto = PF_UNSPEC, | ||
77 | .proto = 0, | ||
78 | .name = "unknown", | ||
79 | .pkt_to_tuple = generic_pkt_to_tuple, | ||
80 | .invert_tuple = generic_invert_tuple, | ||
81 | .print_tuple = generic_print_tuple, | ||
82 | .print_conntrack = generic_print_conntrack, | ||
83 | .packet = packet, | ||
84 | .new = new, | ||
85 | }; | ||
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c new file mode 100644 index 000000000000..3a600f77b4e0 --- /dev/null +++ b/net/netfilter/nf_conntrack_proto_sctp.c | |||
@@ -0,0 +1,670 @@ | |||
1 | /* | ||
2 | * Connection tracking protocol helper module for SCTP. | ||
3 | * | ||
4 | * SCTP is defined in RFC 2960. References to various sections in this code | ||
5 | * are to this RFC. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * 17 Oct 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
12 | * - enable working with L3 protocol independent connection tracking. | ||
13 | * | ||
14 | * Derived from net/ipv4/ip_conntrack_sctp.c | ||
15 | */ | ||
16 | |||
17 | /* | ||
18 | * Added support for proc manipulation of timeouts. | ||
19 | */ | ||
20 | |||
21 | #include <linux/types.h> | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/timer.h> | ||
24 | #include <linux/netfilter.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/in.h> | ||
27 | #include <linux/ip.h> | ||
28 | #include <linux/sctp.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/seq_file.h> | ||
31 | |||
32 | #include <net/netfilter/nf_conntrack.h> | ||
33 | #include <net/netfilter/nf_conntrack_protocol.h> | ||
34 | |||
35 | #if 0 | ||
36 | #define DEBUGP(format, ...) printk(format, ## __VA_ARGS__) | ||
37 | #else | ||
38 | #define DEBUGP(format, args...) | ||
39 | #endif | ||
40 | |||
41 | /* Protects conntrack->proto.sctp */ | ||
42 | static DEFINE_RWLOCK(sctp_lock); | ||
43 | |||
44 | /* FIXME: Examine ipfilter's timeouts and conntrack transitions more | ||
45 | closely. They're more complex. --RR | ||
46 | |||
47 | And so for me for SCTP :D -Kiran */ | ||
48 | |||
49 | static const char *sctp_conntrack_names[] = { | ||
50 | "NONE", | ||
51 | "CLOSED", | ||
52 | "COOKIE_WAIT", | ||
53 | "COOKIE_ECHOED", | ||
54 | "ESTABLISHED", | ||
55 | "SHUTDOWN_SENT", | ||
56 | "SHUTDOWN_RECD", | ||
57 | "SHUTDOWN_ACK_SENT", | ||
58 | }; | ||
59 | |||
60 | #define SECS * HZ | ||
61 | #define MINS * 60 SECS | ||
62 | #define HOURS * 60 MINS | ||
63 | #define DAYS * 24 HOURS | ||
64 | |||
65 | static unsigned long nf_ct_sctp_timeout_closed = 10 SECS; | ||
66 | static unsigned long nf_ct_sctp_timeout_cookie_wait = 3 SECS; | ||
67 | static unsigned long nf_ct_sctp_timeout_cookie_echoed = 3 SECS; | ||
68 | static unsigned long nf_ct_sctp_timeout_established = 5 DAYS; | ||
69 | static unsigned long nf_ct_sctp_timeout_shutdown_sent = 300 SECS / 1000; | ||
70 | static unsigned long nf_ct_sctp_timeout_shutdown_recd = 300 SECS / 1000; | ||
71 | static unsigned long nf_ct_sctp_timeout_shutdown_ack_sent = 3 SECS; | ||
72 | |||
73 | static unsigned long * sctp_timeouts[] | ||
74 | = { NULL, /* SCTP_CONNTRACK_NONE */ | ||
75 | &nf_ct_sctp_timeout_closed, /* SCTP_CONNTRACK_CLOSED */ | ||
76 | &nf_ct_sctp_timeout_cookie_wait, /* SCTP_CONNTRACK_COOKIE_WAIT */ | ||
77 | &nf_ct_sctp_timeout_cookie_echoed, /* SCTP_CONNTRACK_COOKIE_ECHOED */ | ||
78 | &nf_ct_sctp_timeout_established, /* SCTP_CONNTRACK_ESTABLISHED */ | ||
79 | &nf_ct_sctp_timeout_shutdown_sent, /* SCTP_CONNTRACK_SHUTDOWN_SENT */ | ||
80 | &nf_ct_sctp_timeout_shutdown_recd, /* SCTP_CONNTRACK_SHUTDOWN_RECD */ | ||
81 | &nf_ct_sctp_timeout_shutdown_ack_sent /* SCTP_CONNTRACK_SHUTDOWN_ACK_SENT */ | ||
82 | }; | ||
83 | |||
84 | #define sNO SCTP_CONNTRACK_NONE | ||
85 | #define sCL SCTP_CONNTRACK_CLOSED | ||
86 | #define sCW SCTP_CONNTRACK_COOKIE_WAIT | ||
87 | #define sCE SCTP_CONNTRACK_COOKIE_ECHOED | ||
88 | #define sES SCTP_CONNTRACK_ESTABLISHED | ||
89 | #define sSS SCTP_CONNTRACK_SHUTDOWN_SENT | ||
90 | #define sSR SCTP_CONNTRACK_SHUTDOWN_RECD | ||
91 | #define sSA SCTP_CONNTRACK_SHUTDOWN_ACK_SENT | ||
92 | #define sIV SCTP_CONNTRACK_MAX | ||
93 | |||
94 | /* | ||
95 | These are the descriptions of the states: | ||
96 | |||
97 | NOTE: These state names are tantalizingly similar to the states of an | ||
98 | SCTP endpoint. But the interpretation of the states is a little different, | ||
99 | considering that these are the states of the connection and not of an end | ||
100 | point. Please note the subtleties. -Kiran | ||
101 | |||
102 | NONE - Nothing so far. | ||
103 | COOKIE WAIT - We have seen an INIT chunk in the original direction, or also | ||
104 | an INIT_ACK chunk in the reply direction. | ||
105 | COOKIE ECHOED - We have seen a COOKIE_ECHO chunk in the original direction. | ||
106 | ESTABLISHED - We have seen a COOKIE_ACK in the reply direction. | ||
107 | SHUTDOWN_SENT - We have seen a SHUTDOWN chunk in the original direction. | ||
108 | SHUTDOWN_RECD - We have seen a SHUTDOWN chunk in the reply directoin. | ||
109 | SHUTDOWN_ACK_SENT - We have seen a SHUTDOWN_ACK chunk in the direction opposite | ||
110 | to that of the SHUTDOWN chunk. | ||
111 | CLOSED - We have seen a SHUTDOWN_COMPLETE chunk in the direction of | ||
112 | the SHUTDOWN chunk. Connection is closed. | ||
113 | */ | ||
114 | |||
115 | /* TODO | ||
116 | - I have assumed that the first INIT is in the original direction. | ||
117 | This messes things when an INIT comes in the reply direction in CLOSED | ||
118 | state. | ||
119 | - Check the error type in the reply dir before transitioning from | ||
120 | cookie echoed to closed. | ||
121 | - Sec 5.2.4 of RFC 2960 | ||
122 | - Multi Homing support. | ||
123 | */ | ||
124 | |||
125 | /* SCTP conntrack state transitions */ | ||
126 | static enum sctp_conntrack sctp_conntracks[2][9][SCTP_CONNTRACK_MAX] = { | ||
127 | { | ||
128 | /* ORIGINAL */ | ||
129 | /* sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA */ | ||
130 | /* init */ {sCW, sCW, sCW, sCE, sES, sSS, sSR, sSA}, | ||
131 | /* init_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA}, | ||
132 | /* abort */ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL}, | ||
133 | /* shutdown */ {sCL, sCL, sCW, sCE, sSS, sSS, sSR, sSA}, | ||
134 | /* shutdown_ack */ {sSA, sCL, sCW, sCE, sES, sSA, sSA, sSA}, | ||
135 | /* error */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant have Stale cookie*/ | ||
136 | /* cookie_echo */ {sCL, sCL, sCE, sCE, sES, sSS, sSR, sSA},/* 5.2.4 - Big TODO */ | ||
137 | /* cookie_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant come in orig dir */ | ||
138 | /* shutdown_comp*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sCL} | ||
139 | }, | ||
140 | { | ||
141 | /* REPLY */ | ||
142 | /* sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA */ | ||
143 | /* init */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* INIT in sCL Big TODO */ | ||
144 | /* init_ack */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA}, | ||
145 | /* abort */ {sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL}, | ||
146 | /* shutdown */ {sIV, sCL, sCW, sCE, sSR, sSS, sSR, sSA}, | ||
147 | /* shutdown_ack */ {sIV, sCL, sCW, sCE, sES, sSA, sSA, sSA}, | ||
148 | /* error */ {sIV, sCL, sCW, sCL, sES, sSS, sSR, sSA}, | ||
149 | /* cookie_echo */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant come in reply dir */ | ||
150 | /* cookie_ack */ {sIV, sCL, sCW, sES, sES, sSS, sSR, sSA}, | ||
151 | /* shutdown_comp*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sCL} | ||
152 | } | ||
153 | }; | ||
154 | |||
155 | static int sctp_pkt_to_tuple(const struct sk_buff *skb, | ||
156 | unsigned int dataoff, | ||
157 | struct nf_conntrack_tuple *tuple) | ||
158 | { | ||
159 | sctp_sctphdr_t _hdr, *hp; | ||
160 | |||
161 | DEBUGP(__FUNCTION__); | ||
162 | DEBUGP("\n"); | ||
163 | |||
164 | /* Actually only need first 8 bytes. */ | ||
165 | hp = skb_header_pointer(skb, dataoff, 8, &_hdr); | ||
166 | if (hp == NULL) | ||
167 | return 0; | ||
168 | |||
169 | tuple->src.u.sctp.port = hp->source; | ||
170 | tuple->dst.u.sctp.port = hp->dest; | ||
171 | return 1; | ||
172 | } | ||
173 | |||
174 | static int sctp_invert_tuple(struct nf_conntrack_tuple *tuple, | ||
175 | const struct nf_conntrack_tuple *orig) | ||
176 | { | ||
177 | DEBUGP(__FUNCTION__); | ||
178 | DEBUGP("\n"); | ||
179 | |||
180 | tuple->src.u.sctp.port = orig->dst.u.sctp.port; | ||
181 | tuple->dst.u.sctp.port = orig->src.u.sctp.port; | ||
182 | return 1; | ||
183 | } | ||
184 | |||
185 | /* Print out the per-protocol part of the tuple. */ | ||
186 | static int sctp_print_tuple(struct seq_file *s, | ||
187 | const struct nf_conntrack_tuple *tuple) | ||
188 | { | ||
189 | DEBUGP(__FUNCTION__); | ||
190 | DEBUGP("\n"); | ||
191 | |||
192 | return seq_printf(s, "sport=%hu dport=%hu ", | ||
193 | ntohs(tuple->src.u.sctp.port), | ||
194 | ntohs(tuple->dst.u.sctp.port)); | ||
195 | } | ||
196 | |||
197 | /* Print out the private part of the conntrack. */ | ||
198 | static int sctp_print_conntrack(struct seq_file *s, | ||
199 | const struct nf_conn *conntrack) | ||
200 | { | ||
201 | enum sctp_conntrack state; | ||
202 | |||
203 | DEBUGP(__FUNCTION__); | ||
204 | DEBUGP("\n"); | ||
205 | |||
206 | read_lock_bh(&sctp_lock); | ||
207 | state = conntrack->proto.sctp.state; | ||
208 | read_unlock_bh(&sctp_lock); | ||
209 | |||
210 | return seq_printf(s, "%s ", sctp_conntrack_names[state]); | ||
211 | } | ||
212 | |||
213 | #define for_each_sctp_chunk(skb, sch, _sch, offset, dataoff, count) \ | ||
214 | for (offset = dataoff + sizeof(sctp_sctphdr_t), count = 0; \ | ||
215 | offset < skb->len && \ | ||
216 | (sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch)); \ | ||
217 | offset += (htons(sch->length) + 3) & ~3, count++) | ||
218 | |||
219 | /* Some validity checks to make sure the chunks are fine */ | ||
220 | static int do_basic_checks(struct nf_conn *conntrack, | ||
221 | const struct sk_buff *skb, | ||
222 | unsigned int dataoff, | ||
223 | char *map) | ||
224 | { | ||
225 | u_int32_t offset, count; | ||
226 | sctp_chunkhdr_t _sch, *sch; | ||
227 | int flag; | ||
228 | |||
229 | DEBUGP(__FUNCTION__); | ||
230 | DEBUGP("\n"); | ||
231 | |||
232 | flag = 0; | ||
233 | |||
234 | for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) { | ||
235 | DEBUGP("Chunk Num: %d Type: %d\n", count, sch->type); | ||
236 | |||
237 | if (sch->type == SCTP_CID_INIT | ||
238 | || sch->type == SCTP_CID_INIT_ACK | ||
239 | || sch->type == SCTP_CID_SHUTDOWN_COMPLETE) { | ||
240 | flag = 1; | ||
241 | } | ||
242 | |||
243 | /* Cookie Ack/Echo chunks not the first OR | ||
244 | Init / Init Ack / Shutdown compl chunks not the only chunks */ | ||
245 | if ((sch->type == SCTP_CID_COOKIE_ACK | ||
246 | || sch->type == SCTP_CID_COOKIE_ECHO | ||
247 | || flag) | ||
248 | && count !=0 ) { | ||
249 | DEBUGP("Basic checks failed\n"); | ||
250 | return 1; | ||
251 | } | ||
252 | |||
253 | if (map) { | ||
254 | set_bit(sch->type, (void *)map); | ||
255 | } | ||
256 | } | ||
257 | |||
258 | DEBUGP("Basic checks passed\n"); | ||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | static int new_state(enum ip_conntrack_dir dir, | ||
263 | enum sctp_conntrack cur_state, | ||
264 | int chunk_type) | ||
265 | { | ||
266 | int i; | ||
267 | |||
268 | DEBUGP(__FUNCTION__); | ||
269 | DEBUGP("\n"); | ||
270 | |||
271 | DEBUGP("Chunk type: %d\n", chunk_type); | ||
272 | |||
273 | switch (chunk_type) { | ||
274 | case SCTP_CID_INIT: | ||
275 | DEBUGP("SCTP_CID_INIT\n"); | ||
276 | i = 0; break; | ||
277 | case SCTP_CID_INIT_ACK: | ||
278 | DEBUGP("SCTP_CID_INIT_ACK\n"); | ||
279 | i = 1; break; | ||
280 | case SCTP_CID_ABORT: | ||
281 | DEBUGP("SCTP_CID_ABORT\n"); | ||
282 | i = 2; break; | ||
283 | case SCTP_CID_SHUTDOWN: | ||
284 | DEBUGP("SCTP_CID_SHUTDOWN\n"); | ||
285 | i = 3; break; | ||
286 | case SCTP_CID_SHUTDOWN_ACK: | ||
287 | DEBUGP("SCTP_CID_SHUTDOWN_ACK\n"); | ||
288 | i = 4; break; | ||
289 | case SCTP_CID_ERROR: | ||
290 | DEBUGP("SCTP_CID_ERROR\n"); | ||
291 | i = 5; break; | ||
292 | case SCTP_CID_COOKIE_ECHO: | ||
293 | DEBUGP("SCTP_CID_COOKIE_ECHO\n"); | ||
294 | i = 6; break; | ||
295 | case SCTP_CID_COOKIE_ACK: | ||
296 | DEBUGP("SCTP_CID_COOKIE_ACK\n"); | ||
297 | i = 7; break; | ||
298 | case SCTP_CID_SHUTDOWN_COMPLETE: | ||
299 | DEBUGP("SCTP_CID_SHUTDOWN_COMPLETE\n"); | ||
300 | i = 8; break; | ||
301 | default: | ||
302 | /* Other chunks like DATA, SACK, HEARTBEAT and | ||
303 | its ACK do not cause a change in state */ | ||
304 | DEBUGP("Unknown chunk type, Will stay in %s\n", | ||
305 | sctp_conntrack_names[cur_state]); | ||
306 | return cur_state; | ||
307 | } | ||
308 | |||
309 | DEBUGP("dir: %d cur_state: %s chunk_type: %d new_state: %s\n", | ||
310 | dir, sctp_conntrack_names[cur_state], chunk_type, | ||
311 | sctp_conntrack_names[sctp_conntracks[dir][i][cur_state]]); | ||
312 | |||
313 | return sctp_conntracks[dir][i][cur_state]; | ||
314 | } | ||
315 | |||
316 | /* Returns verdict for packet, or -1 for invalid. */ | ||
317 | static int sctp_packet(struct nf_conn *conntrack, | ||
318 | const struct sk_buff *skb, | ||
319 | unsigned int dataoff, | ||
320 | enum ip_conntrack_info ctinfo, | ||
321 | int pf, | ||
322 | unsigned int hooknum) | ||
323 | { | ||
324 | enum sctp_conntrack newconntrack, oldsctpstate; | ||
325 | sctp_sctphdr_t _sctph, *sh; | ||
326 | sctp_chunkhdr_t _sch, *sch; | ||
327 | u_int32_t offset, count; | ||
328 | char map[256 / sizeof (char)] = {0}; | ||
329 | |||
330 | DEBUGP(__FUNCTION__); | ||
331 | DEBUGP("\n"); | ||
332 | |||
333 | sh = skb_header_pointer(skb, dataoff, sizeof(_sctph), &_sctph); | ||
334 | if (sh == NULL) | ||
335 | return -1; | ||
336 | |||
337 | if (do_basic_checks(conntrack, skb, dataoff, map) != 0) | ||
338 | return -1; | ||
339 | |||
340 | /* Check the verification tag (Sec 8.5) */ | ||
341 | if (!test_bit(SCTP_CID_INIT, (void *)map) | ||
342 | && !test_bit(SCTP_CID_SHUTDOWN_COMPLETE, (void *)map) | ||
343 | && !test_bit(SCTP_CID_COOKIE_ECHO, (void *)map) | ||
344 | && !test_bit(SCTP_CID_ABORT, (void *)map) | ||
345 | && !test_bit(SCTP_CID_SHUTDOWN_ACK, (void *)map) | ||
346 | && (sh->vtag != conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])) { | ||
347 | DEBUGP("Verification tag check failed\n"); | ||
348 | return -1; | ||
349 | } | ||
350 | |||
351 | oldsctpstate = newconntrack = SCTP_CONNTRACK_MAX; | ||
352 | for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) { | ||
353 | write_lock_bh(&sctp_lock); | ||
354 | |||
355 | /* Special cases of Verification tag check (Sec 8.5.1) */ | ||
356 | if (sch->type == SCTP_CID_INIT) { | ||
357 | /* Sec 8.5.1 (A) */ | ||
358 | if (sh->vtag != 0) { | ||
359 | write_unlock_bh(&sctp_lock); | ||
360 | return -1; | ||
361 | } | ||
362 | } else if (sch->type == SCTP_CID_ABORT) { | ||
363 | /* Sec 8.5.1 (B) */ | ||
364 | if (!(sh->vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)]) | ||
365 | && !(sh->vtag == conntrack->proto.sctp.vtag | ||
366 | [1 - CTINFO2DIR(ctinfo)])) { | ||
367 | write_unlock_bh(&sctp_lock); | ||
368 | return -1; | ||
369 | } | ||
370 | } else if (sch->type == SCTP_CID_SHUTDOWN_COMPLETE) { | ||
371 | /* Sec 8.5.1 (C) */ | ||
372 | if (!(sh->vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)]) | ||
373 | && !(sh->vtag == conntrack->proto.sctp.vtag | ||
374 | [1 - CTINFO2DIR(ctinfo)] | ||
375 | && (sch->flags & 1))) { | ||
376 | write_unlock_bh(&sctp_lock); | ||
377 | return -1; | ||
378 | } | ||
379 | } else if (sch->type == SCTP_CID_COOKIE_ECHO) { | ||
380 | /* Sec 8.5.1 (D) */ | ||
381 | if (!(sh->vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])) { | ||
382 | write_unlock_bh(&sctp_lock); | ||
383 | return -1; | ||
384 | } | ||
385 | } | ||
386 | |||
387 | oldsctpstate = conntrack->proto.sctp.state; | ||
388 | newconntrack = new_state(CTINFO2DIR(ctinfo), oldsctpstate, sch->type); | ||
389 | |||
390 | /* Invalid */ | ||
391 | if (newconntrack == SCTP_CONNTRACK_MAX) { | ||
392 | DEBUGP("nf_conntrack_sctp: Invalid dir=%i ctype=%u conntrack=%u\n", | ||
393 | CTINFO2DIR(ctinfo), sch->type, oldsctpstate); | ||
394 | write_unlock_bh(&sctp_lock); | ||
395 | return -1; | ||
396 | } | ||
397 | |||
398 | /* If it is an INIT or an INIT ACK note down the vtag */ | ||
399 | if (sch->type == SCTP_CID_INIT | ||
400 | || sch->type == SCTP_CID_INIT_ACK) { | ||
401 | sctp_inithdr_t _inithdr, *ih; | ||
402 | |||
403 | ih = skb_header_pointer(skb, offset + sizeof(sctp_chunkhdr_t), | ||
404 | sizeof(_inithdr), &_inithdr); | ||
405 | if (ih == NULL) { | ||
406 | write_unlock_bh(&sctp_lock); | ||
407 | return -1; | ||
408 | } | ||
409 | DEBUGP("Setting vtag %x for dir %d\n", | ||
410 | ih->init_tag, !CTINFO2DIR(ctinfo)); | ||
411 | conntrack->proto.sctp.vtag[!CTINFO2DIR(ctinfo)] = ih->init_tag; | ||
412 | } | ||
413 | |||
414 | conntrack->proto.sctp.state = newconntrack; | ||
415 | if (oldsctpstate != newconntrack) | ||
416 | nf_conntrack_event_cache(IPCT_PROTOINFO, skb); | ||
417 | write_unlock_bh(&sctp_lock); | ||
418 | } | ||
419 | |||
420 | nf_ct_refresh_acct(conntrack, ctinfo, skb, *sctp_timeouts[newconntrack]); | ||
421 | |||
422 | if (oldsctpstate == SCTP_CONNTRACK_COOKIE_ECHOED | ||
423 | && CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY | ||
424 | && newconntrack == SCTP_CONNTRACK_ESTABLISHED) { | ||
425 | DEBUGP("Setting assured bit\n"); | ||
426 | set_bit(IPS_ASSURED_BIT, &conntrack->status); | ||
427 | nf_conntrack_event_cache(IPCT_STATUS, skb); | ||
428 | } | ||
429 | |||
430 | return NF_ACCEPT; | ||
431 | } | ||
432 | |||
433 | /* Called when a new connection for this protocol found. */ | ||
434 | static int sctp_new(struct nf_conn *conntrack, const struct sk_buff *skb, | ||
435 | unsigned int dataoff) | ||
436 | { | ||
437 | enum sctp_conntrack newconntrack; | ||
438 | sctp_sctphdr_t _sctph, *sh; | ||
439 | sctp_chunkhdr_t _sch, *sch; | ||
440 | u_int32_t offset, count; | ||
441 | char map[256 / sizeof (char)] = {0}; | ||
442 | |||
443 | DEBUGP(__FUNCTION__); | ||
444 | DEBUGP("\n"); | ||
445 | |||
446 | sh = skb_header_pointer(skb, dataoff, sizeof(_sctph), &_sctph); | ||
447 | if (sh == NULL) | ||
448 | return 0; | ||
449 | |||
450 | if (do_basic_checks(conntrack, skb, dataoff, map) != 0) | ||
451 | return 0; | ||
452 | |||
453 | /* If an OOTB packet has any of these chunks discard (Sec 8.4) */ | ||
454 | if ((test_bit (SCTP_CID_ABORT, (void *)map)) | ||
455 | || (test_bit (SCTP_CID_SHUTDOWN_COMPLETE, (void *)map)) | ||
456 | || (test_bit (SCTP_CID_COOKIE_ACK, (void *)map))) { | ||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | newconntrack = SCTP_CONNTRACK_MAX; | ||
461 | for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) { | ||
462 | /* Don't need lock here: this conntrack not in circulation yet */ | ||
463 | newconntrack = new_state(IP_CT_DIR_ORIGINAL, | ||
464 | SCTP_CONNTRACK_NONE, sch->type); | ||
465 | |||
466 | /* Invalid: delete conntrack */ | ||
467 | if (newconntrack == SCTP_CONNTRACK_MAX) { | ||
468 | DEBUGP("nf_conntrack_sctp: invalid new deleting.\n"); | ||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | /* Copy the vtag into the state info */ | ||
473 | if (sch->type == SCTP_CID_INIT) { | ||
474 | if (sh->vtag == 0) { | ||
475 | sctp_inithdr_t _inithdr, *ih; | ||
476 | |||
477 | ih = skb_header_pointer(skb, offset + sizeof(sctp_chunkhdr_t), | ||
478 | sizeof(_inithdr), &_inithdr); | ||
479 | if (ih == NULL) | ||
480 | return 0; | ||
481 | |||
482 | DEBUGP("Setting vtag %x for new conn\n", | ||
483 | ih->init_tag); | ||
484 | |||
485 | conntrack->proto.sctp.vtag[IP_CT_DIR_REPLY] = | ||
486 | ih->init_tag; | ||
487 | } else { | ||
488 | /* Sec 8.5.1 (A) */ | ||
489 | return 0; | ||
490 | } | ||
491 | } | ||
492 | /* If it is a shutdown ack OOTB packet, we expect a return | ||
493 | shutdown complete, otherwise an ABORT Sec 8.4 (5) and (8) */ | ||
494 | else { | ||
495 | DEBUGP("Setting vtag %x for new conn OOTB\n", | ||
496 | sh->vtag); | ||
497 | conntrack->proto.sctp.vtag[IP_CT_DIR_REPLY] = sh->vtag; | ||
498 | } | ||
499 | |||
500 | conntrack->proto.sctp.state = newconntrack; | ||
501 | } | ||
502 | |||
503 | return 1; | ||
504 | } | ||
505 | |||
506 | struct nf_conntrack_protocol nf_conntrack_protocol_sctp4 = { | ||
507 | .l3proto = PF_INET, | ||
508 | .proto = IPPROTO_SCTP, | ||
509 | .name = "sctp", | ||
510 | .pkt_to_tuple = sctp_pkt_to_tuple, | ||
511 | .invert_tuple = sctp_invert_tuple, | ||
512 | .print_tuple = sctp_print_tuple, | ||
513 | .print_conntrack = sctp_print_conntrack, | ||
514 | .packet = sctp_packet, | ||
515 | .new = sctp_new, | ||
516 | .destroy = NULL, | ||
517 | .me = THIS_MODULE | ||
518 | }; | ||
519 | |||
520 | struct nf_conntrack_protocol nf_conntrack_protocol_sctp6 = { | ||
521 | .l3proto = PF_INET6, | ||
522 | .proto = IPPROTO_SCTP, | ||
523 | .name = "sctp", | ||
524 | .pkt_to_tuple = sctp_pkt_to_tuple, | ||
525 | .invert_tuple = sctp_invert_tuple, | ||
526 | .print_tuple = sctp_print_tuple, | ||
527 | .print_conntrack = sctp_print_conntrack, | ||
528 | .packet = sctp_packet, | ||
529 | .new = sctp_new, | ||
530 | .destroy = NULL, | ||
531 | .me = THIS_MODULE | ||
532 | }; | ||
533 | |||
534 | #ifdef CONFIG_SYSCTL | ||
535 | static ctl_table nf_ct_sysctl_table[] = { | ||
536 | { | ||
537 | .ctl_name = NET_NF_CONNTRACK_SCTP_TIMEOUT_CLOSED, | ||
538 | .procname = "nf_conntrack_sctp_timeout_closed", | ||
539 | .data = &nf_ct_sctp_timeout_closed, | ||
540 | .maxlen = sizeof(unsigned int), | ||
541 | .mode = 0644, | ||
542 | .proc_handler = &proc_dointvec_jiffies, | ||
543 | }, | ||
544 | { | ||
545 | .ctl_name = NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_WAIT, | ||
546 | .procname = "nf_conntrack_sctp_timeout_cookie_wait", | ||
547 | .data = &nf_ct_sctp_timeout_cookie_wait, | ||
548 | .maxlen = sizeof(unsigned int), | ||
549 | .mode = 0644, | ||
550 | .proc_handler = &proc_dointvec_jiffies, | ||
551 | }, | ||
552 | { | ||
553 | .ctl_name = NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_ECHOED, | ||
554 | .procname = "nf_conntrack_sctp_timeout_cookie_echoed", | ||
555 | .data = &nf_ct_sctp_timeout_cookie_echoed, | ||
556 | .maxlen = sizeof(unsigned int), | ||
557 | .mode = 0644, | ||
558 | .proc_handler = &proc_dointvec_jiffies, | ||
559 | }, | ||
560 | { | ||
561 | .ctl_name = NET_NF_CONNTRACK_SCTP_TIMEOUT_ESTABLISHED, | ||
562 | .procname = "nf_conntrack_sctp_timeout_established", | ||
563 | .data = &nf_ct_sctp_timeout_established, | ||
564 | .maxlen = sizeof(unsigned int), | ||
565 | .mode = 0644, | ||
566 | .proc_handler = &proc_dointvec_jiffies, | ||
567 | }, | ||
568 | { | ||
569 | .ctl_name = NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_SENT, | ||
570 | .procname = "nf_conntrack_sctp_timeout_shutdown_sent", | ||
571 | .data = &nf_ct_sctp_timeout_shutdown_sent, | ||
572 | .maxlen = sizeof(unsigned int), | ||
573 | .mode = 0644, | ||
574 | .proc_handler = &proc_dointvec_jiffies, | ||
575 | }, | ||
576 | { | ||
577 | .ctl_name = NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD, | ||
578 | .procname = "nf_conntrack_sctp_timeout_shutdown_recd", | ||
579 | .data = &nf_ct_sctp_timeout_shutdown_recd, | ||
580 | .maxlen = sizeof(unsigned int), | ||
581 | .mode = 0644, | ||
582 | .proc_handler = &proc_dointvec_jiffies, | ||
583 | }, | ||
584 | { | ||
585 | .ctl_name = NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT, | ||
586 | .procname = "nf_conntrack_sctp_timeout_shutdown_ack_sent", | ||
587 | .data = &nf_ct_sctp_timeout_shutdown_ack_sent, | ||
588 | .maxlen = sizeof(unsigned int), | ||
589 | .mode = 0644, | ||
590 | .proc_handler = &proc_dointvec_jiffies, | ||
591 | }, | ||
592 | { .ctl_name = 0 } | ||
593 | }; | ||
594 | |||
595 | static ctl_table nf_ct_netfilter_table[] = { | ||
596 | { | ||
597 | .ctl_name = NET_NETFILTER, | ||
598 | .procname = "netfilter", | ||
599 | .mode = 0555, | ||
600 | .child = nf_ct_sysctl_table, | ||
601 | }, | ||
602 | { .ctl_name = 0 } | ||
603 | }; | ||
604 | |||
605 | static ctl_table nf_ct_net_table[] = { | ||
606 | { | ||
607 | .ctl_name = CTL_NET, | ||
608 | .procname = "net", | ||
609 | .mode = 0555, | ||
610 | .child = nf_ct_netfilter_table, | ||
611 | }, | ||
612 | { .ctl_name = 0 } | ||
613 | }; | ||
614 | |||
615 | static struct ctl_table_header *nf_ct_sysctl_header; | ||
616 | #endif | ||
617 | |||
618 | int __init init(void) | ||
619 | { | ||
620 | int ret; | ||
621 | |||
622 | ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_sctp4); | ||
623 | if (ret) { | ||
624 | printk("nf_conntrack_proto_sctp4: protocol register failed\n"); | ||
625 | goto out; | ||
626 | } | ||
627 | ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_sctp6); | ||
628 | if (ret) { | ||
629 | printk("nf_conntrack_proto_sctp6: protocol register failed\n"); | ||
630 | goto cleanup_sctp4; | ||
631 | } | ||
632 | |||
633 | #ifdef CONFIG_SYSCTL | ||
634 | nf_ct_sysctl_header = register_sysctl_table(nf_ct_net_table, 0); | ||
635 | if (nf_ct_sysctl_header == NULL) { | ||
636 | printk("nf_conntrack_proto_sctp: can't register to sysctl.\n"); | ||
637 | goto cleanup; | ||
638 | } | ||
639 | #endif | ||
640 | |||
641 | return ret; | ||
642 | |||
643 | #ifdef CONFIG_SYSCTL | ||
644 | cleanup: | ||
645 | nf_conntrack_protocol_unregister(&nf_conntrack_protocol_sctp6); | ||
646 | #endif | ||
647 | cleanup_sctp4: | ||
648 | nf_conntrack_protocol_unregister(&nf_conntrack_protocol_sctp4); | ||
649 | out: | ||
650 | DEBUGP("SCTP conntrack module loading %s\n", | ||
651 | ret ? "failed": "succeeded"); | ||
652 | return ret; | ||
653 | } | ||
654 | |||
655 | void __exit fini(void) | ||
656 | { | ||
657 | nf_conntrack_protocol_unregister(&nf_conntrack_protocol_sctp6); | ||
658 | nf_conntrack_protocol_unregister(&nf_conntrack_protocol_sctp4); | ||
659 | #ifdef CONFIG_SYSCTL | ||
660 | unregister_sysctl_table(nf_ct_sysctl_header); | ||
661 | #endif | ||
662 | DEBUGP("SCTP conntrack module unloaded\n"); | ||
663 | } | ||
664 | |||
665 | module_init(init); | ||
666 | module_exit(fini); | ||
667 | |||
668 | MODULE_LICENSE("GPL"); | ||
669 | MODULE_AUTHOR("Kiran Kumar Immidi"); | ||
670 | MODULE_DESCRIPTION("Netfilter connection tracking protocol helper for SCTP"); | ||
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c new file mode 100644 index 000000000000..83d90dd624f0 --- /dev/null +++ b/net/netfilter/nf_conntrack_proto_tcp.c | |||
@@ -0,0 +1,1162 @@ | |||
1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>: | ||
9 | * - Real stateful connection tracking | ||
10 | * - Modified state transitions table | ||
11 | * - Window scaling support added | ||
12 | * - SACK support added | ||
13 | * | ||
14 | * Willy Tarreau: | ||
15 | * - State table bugfixes | ||
16 | * - More robust state changes | ||
17 | * - Tuning timer parameters | ||
18 | * | ||
19 | * 27 Oct 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
20 | * - genelized Layer 3 protocol part. | ||
21 | * | ||
22 | * Derived from net/ipv4/netfilter/ip_conntrack_proto_tcp.c | ||
23 | * | ||
24 | * version 2.2 | ||
25 | */ | ||
26 | |||
27 | #include <linux/config.h> | ||
28 | #include <linux/types.h> | ||
29 | #include <linux/sched.h> | ||
30 | #include <linux/timer.h> | ||
31 | #include <linux/netfilter.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/in.h> | ||
34 | #include <linux/tcp.h> | ||
35 | #include <linux/spinlock.h> | ||
36 | #include <linux/skbuff.h> | ||
37 | #include <linux/ipv6.h> | ||
38 | #include <net/ip6_checksum.h> | ||
39 | |||
40 | #include <net/tcp.h> | ||
41 | |||
42 | #include <linux/netfilter.h> | ||
43 | #include <linux/netfilter_ipv4.h> | ||
44 | #include <linux/netfilter_ipv6.h> | ||
45 | #include <net/netfilter/nf_conntrack.h> | ||
46 | #include <net/netfilter/nf_conntrack_protocol.h> | ||
47 | |||
48 | #if 0 | ||
49 | #define DEBUGP printk | ||
50 | #define DEBUGP_VARS | ||
51 | #else | ||
52 | #define DEBUGP(format, args...) | ||
53 | #endif | ||
54 | |||
55 | /* Protects conntrack->proto.tcp */ | ||
56 | static DEFINE_RWLOCK(tcp_lock); | ||
57 | |||
58 | /* "Be conservative in what you do, | ||
59 | be liberal in what you accept from others." | ||
60 | If it's non-zero, we mark only out of window RST segments as INVALID. */ | ||
61 | int nf_ct_tcp_be_liberal = 0; | ||
62 | |||
63 | /* When connection is picked up from the middle, how many packets are required | ||
64 | to pass in each direction when we assume we are in sync - if any side uses | ||
65 | window scaling, we lost the game. | ||
66 | If it is set to zero, we disable picking up already established | ||
67 | connections. */ | ||
68 | int nf_ct_tcp_loose = 3; | ||
69 | |||
70 | /* Max number of the retransmitted packets without receiving an (acceptable) | ||
71 | ACK from the destination. If this number is reached, a shorter timer | ||
72 | will be started. */ | ||
73 | int nf_ct_tcp_max_retrans = 3; | ||
74 | |||
75 | /* FIXME: Examine ipfilter's timeouts and conntrack transitions more | ||
76 | closely. They're more complex. --RR */ | ||
77 | |||
78 | static const char *tcp_conntrack_names[] = { | ||
79 | "NONE", | ||
80 | "SYN_SENT", | ||
81 | "SYN_RECV", | ||
82 | "ESTABLISHED", | ||
83 | "FIN_WAIT", | ||
84 | "CLOSE_WAIT", | ||
85 | "LAST_ACK", | ||
86 | "TIME_WAIT", | ||
87 | "CLOSE", | ||
88 | "LISTEN" | ||
89 | }; | ||
90 | |||
91 | #define SECS * HZ | ||
92 | #define MINS * 60 SECS | ||
93 | #define HOURS * 60 MINS | ||
94 | #define DAYS * 24 HOURS | ||
95 | |||
96 | unsigned long nf_ct_tcp_timeout_syn_sent = 2 MINS; | ||
97 | unsigned long nf_ct_tcp_timeout_syn_recv = 60 SECS; | ||
98 | unsigned long nf_ct_tcp_timeout_established = 5 DAYS; | ||
99 | unsigned long nf_ct_tcp_timeout_fin_wait = 2 MINS; | ||
100 | unsigned long nf_ct_tcp_timeout_close_wait = 60 SECS; | ||
101 | unsigned long nf_ct_tcp_timeout_last_ack = 30 SECS; | ||
102 | unsigned long nf_ct_tcp_timeout_time_wait = 2 MINS; | ||
103 | unsigned long nf_ct_tcp_timeout_close = 10 SECS; | ||
104 | |||
105 | /* RFC1122 says the R2 limit should be at least 100 seconds. | ||
106 | Linux uses 15 packets as limit, which corresponds | ||
107 | to ~13-30min depending on RTO. */ | ||
108 | unsigned long nf_ct_tcp_timeout_max_retrans = 5 MINS; | ||
109 | |||
110 | static unsigned long * tcp_timeouts[] | ||
111 | = { NULL, /* TCP_CONNTRACK_NONE */ | ||
112 | &nf_ct_tcp_timeout_syn_sent, /* TCP_CONNTRACK_SYN_SENT, */ | ||
113 | &nf_ct_tcp_timeout_syn_recv, /* TCP_CONNTRACK_SYN_RECV, */ | ||
114 | &nf_ct_tcp_timeout_established, /* TCP_CONNTRACK_ESTABLISHED, */ | ||
115 | &nf_ct_tcp_timeout_fin_wait, /* TCP_CONNTRACK_FIN_WAIT, */ | ||
116 | &nf_ct_tcp_timeout_close_wait, /* TCP_CONNTRACK_CLOSE_WAIT, */ | ||
117 | &nf_ct_tcp_timeout_last_ack, /* TCP_CONNTRACK_LAST_ACK, */ | ||
118 | &nf_ct_tcp_timeout_time_wait, /* TCP_CONNTRACK_TIME_WAIT, */ | ||
119 | &nf_ct_tcp_timeout_close, /* TCP_CONNTRACK_CLOSE, */ | ||
120 | NULL, /* TCP_CONNTRACK_LISTEN */ | ||
121 | }; | ||
122 | |||
123 | #define sNO TCP_CONNTRACK_NONE | ||
124 | #define sSS TCP_CONNTRACK_SYN_SENT | ||
125 | #define sSR TCP_CONNTRACK_SYN_RECV | ||
126 | #define sES TCP_CONNTRACK_ESTABLISHED | ||
127 | #define sFW TCP_CONNTRACK_FIN_WAIT | ||
128 | #define sCW TCP_CONNTRACK_CLOSE_WAIT | ||
129 | #define sLA TCP_CONNTRACK_LAST_ACK | ||
130 | #define sTW TCP_CONNTRACK_TIME_WAIT | ||
131 | #define sCL TCP_CONNTRACK_CLOSE | ||
132 | #define sLI TCP_CONNTRACK_LISTEN | ||
133 | #define sIV TCP_CONNTRACK_MAX | ||
134 | #define sIG TCP_CONNTRACK_IGNORE | ||
135 | |||
136 | /* What TCP flags are set from RST/SYN/FIN/ACK. */ | ||
137 | enum tcp_bit_set { | ||
138 | TCP_SYN_SET, | ||
139 | TCP_SYNACK_SET, | ||
140 | TCP_FIN_SET, | ||
141 | TCP_ACK_SET, | ||
142 | TCP_RST_SET, | ||
143 | TCP_NONE_SET, | ||
144 | }; | ||
145 | |||
146 | /* | ||
147 | * The TCP state transition table needs a few words... | ||
148 | * | ||
149 | * We are the man in the middle. All the packets go through us | ||
150 | * but might get lost in transit to the destination. | ||
151 | * It is assumed that the destinations can't receive segments | ||
152 | * we haven't seen. | ||
153 | * | ||
154 | * The checked segment is in window, but our windows are *not* | ||
155 | * equivalent with the ones of the sender/receiver. We always | ||
156 | * try to guess the state of the current sender. | ||
157 | * | ||
158 | * The meaning of the states are: | ||
159 | * | ||
160 | * NONE: initial state | ||
161 | * SYN_SENT: SYN-only packet seen | ||
162 | * SYN_RECV: SYN-ACK packet seen | ||
163 | * ESTABLISHED: ACK packet seen | ||
164 | * FIN_WAIT: FIN packet seen | ||
165 | * CLOSE_WAIT: ACK seen (after FIN) | ||
166 | * LAST_ACK: FIN seen (after FIN) | ||
167 | * TIME_WAIT: last ACK seen | ||
168 | * CLOSE: closed connection | ||
169 | * | ||
170 | * LISTEN state is not used. | ||
171 | * | ||
172 | * Packets marked as IGNORED (sIG): | ||
173 | * if they may be either invalid or valid | ||
174 | * and the receiver may send back a connection | ||
175 | * closing RST or a SYN/ACK. | ||
176 | * | ||
177 | * Packets marked as INVALID (sIV): | ||
178 | * if they are invalid | ||
179 | * or we do not support the request (simultaneous open) | ||
180 | */ | ||
181 | static enum tcp_conntrack tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { | ||
182 | { | ||
183 | /* ORIGINAL */ | ||
184 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ | ||
185 | /*syn*/ { sSS, sSS, sIG, sIG, sIG, sIG, sIG, sSS, sSS, sIV }, | ||
186 | /* | ||
187 | * sNO -> sSS Initialize a new connection | ||
188 | * sSS -> sSS Retransmitted SYN | ||
189 | * sSR -> sIG Late retransmitted SYN? | ||
190 | * sES -> sIG Error: SYNs in window outside the SYN_SENT state | ||
191 | * are errors. Receiver will reply with RST | ||
192 | * and close the connection. | ||
193 | * Or we are not in sync and hold a dead connection. | ||
194 | * sFW -> sIG | ||
195 | * sCW -> sIG | ||
196 | * sLA -> sIG | ||
197 | * sTW -> sSS Reopened connection (RFC 1122). | ||
198 | * sCL -> sSS | ||
199 | */ | ||
200 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ | ||
201 | /*synack*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }, | ||
202 | /* | ||
203 | * A SYN/ACK from the client is always invalid: | ||
204 | * - either it tries to set up a simultaneous open, which is | ||
205 | * not supported; | ||
206 | * - or the firewall has just been inserted between the two hosts | ||
207 | * during the session set-up. The SYN will be retransmitted | ||
208 | * by the true client (or it'll time out). | ||
209 | */ | ||
210 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ | ||
211 | /*fin*/ { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV }, | ||
212 | /* | ||
213 | * sNO -> sIV Too late and no reason to do anything... | ||
214 | * sSS -> sIV Client migth not send FIN in this state: | ||
215 | * we enforce waiting for a SYN/ACK reply first. | ||
216 | * sSR -> sFW Close started. | ||
217 | * sES -> sFW | ||
218 | * sFW -> sLA FIN seen in both directions, waiting for | ||
219 | * the last ACK. | ||
220 | * Migth be a retransmitted FIN as well... | ||
221 | * sCW -> sLA | ||
222 | * sLA -> sLA Retransmitted FIN. Remain in the same state. | ||
223 | * sTW -> sTW | ||
224 | * sCL -> sCL | ||
225 | */ | ||
226 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ | ||
227 | /*ack*/ { sES, sIV, sES, sES, sCW, sCW, sTW, sTW, sCL, sIV }, | ||
228 | /* | ||
229 | * sNO -> sES Assumed. | ||
230 | * sSS -> sIV ACK is invalid: we haven't seen a SYN/ACK yet. | ||
231 | * sSR -> sES Established state is reached. | ||
232 | * sES -> sES :-) | ||
233 | * sFW -> sCW Normal close request answered by ACK. | ||
234 | * sCW -> sCW | ||
235 | * sLA -> sTW Last ACK detected. | ||
236 | * sTW -> sTW Retransmitted last ACK. Remain in the same state. | ||
237 | * sCL -> sCL | ||
238 | */ | ||
239 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ | ||
240 | /*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV }, | ||
241 | /*none*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV } | ||
242 | }, | ||
243 | { | ||
244 | /* REPLY */ | ||
245 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ | ||
246 | /*syn*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }, | ||
247 | /* | ||
248 | * sNO -> sIV Never reached. | ||
249 | * sSS -> sIV Simultaneous open, not supported | ||
250 | * sSR -> sIV Simultaneous open, not supported. | ||
251 | * sES -> sIV Server may not initiate a connection. | ||
252 | * sFW -> sIV | ||
253 | * sCW -> sIV | ||
254 | * sLA -> sIV | ||
255 | * sTW -> sIV Reopened connection, but server may not do it. | ||
256 | * sCL -> sIV | ||
257 | */ | ||
258 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ | ||
259 | /*synack*/ { sIV, sSR, sSR, sIG, sIG, sIG, sIG, sIG, sIG, sIV }, | ||
260 | /* | ||
261 | * sSS -> sSR Standard open. | ||
262 | * sSR -> sSR Retransmitted SYN/ACK. | ||
263 | * sES -> sIG Late retransmitted SYN/ACK? | ||
264 | * sFW -> sIG Might be SYN/ACK answering ignored SYN | ||
265 | * sCW -> sIG | ||
266 | * sLA -> sIG | ||
267 | * sTW -> sIG | ||
268 | * sCL -> sIG | ||
269 | */ | ||
270 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ | ||
271 | /*fin*/ { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV }, | ||
272 | /* | ||
273 | * sSS -> sIV Server might not send FIN in this state. | ||
274 | * sSR -> sFW Close started. | ||
275 | * sES -> sFW | ||
276 | * sFW -> sLA FIN seen in both directions. | ||
277 | * sCW -> sLA | ||
278 | * sLA -> sLA Retransmitted FIN. | ||
279 | * sTW -> sTW | ||
280 | * sCL -> sCL | ||
281 | */ | ||
282 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ | ||
283 | /*ack*/ { sIV, sIV, sSR, sES, sCW, sCW, sTW, sTW, sCL, sIV }, | ||
284 | /* | ||
285 | * sSS -> sIV Might be a half-open connection. | ||
286 | * sSR -> sSR Might answer late resent SYN. | ||
287 | * sES -> sES :-) | ||
288 | * sFW -> sCW Normal close request answered by ACK. | ||
289 | * sCW -> sCW | ||
290 | * sLA -> sTW Last ACK detected. | ||
291 | * sTW -> sTW Retransmitted last ACK. | ||
292 | * sCL -> sCL | ||
293 | */ | ||
294 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ | ||
295 | /*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV }, | ||
296 | /*none*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV } | ||
297 | } | ||
298 | }; | ||
299 | |||
300 | static int tcp_pkt_to_tuple(const struct sk_buff *skb, | ||
301 | unsigned int dataoff, | ||
302 | struct nf_conntrack_tuple *tuple) | ||
303 | { | ||
304 | struct tcphdr _hdr, *hp; | ||
305 | |||
306 | /* Actually only need first 8 bytes. */ | ||
307 | hp = skb_header_pointer(skb, dataoff, 8, &_hdr); | ||
308 | if (hp == NULL) | ||
309 | return 0; | ||
310 | |||
311 | tuple->src.u.tcp.port = hp->source; | ||
312 | tuple->dst.u.tcp.port = hp->dest; | ||
313 | |||
314 | return 1; | ||
315 | } | ||
316 | |||
317 | static int tcp_invert_tuple(struct nf_conntrack_tuple *tuple, | ||
318 | const struct nf_conntrack_tuple *orig) | ||
319 | { | ||
320 | tuple->src.u.tcp.port = orig->dst.u.tcp.port; | ||
321 | tuple->dst.u.tcp.port = orig->src.u.tcp.port; | ||
322 | return 1; | ||
323 | } | ||
324 | |||
325 | /* Print out the per-protocol part of the tuple. */ | ||
326 | static int tcp_print_tuple(struct seq_file *s, | ||
327 | const struct nf_conntrack_tuple *tuple) | ||
328 | { | ||
329 | return seq_printf(s, "sport=%hu dport=%hu ", | ||
330 | ntohs(tuple->src.u.tcp.port), | ||
331 | ntohs(tuple->dst.u.tcp.port)); | ||
332 | } | ||
333 | |||
334 | /* Print out the private part of the conntrack. */ | ||
335 | static int tcp_print_conntrack(struct seq_file *s, | ||
336 | const struct nf_conn *conntrack) | ||
337 | { | ||
338 | enum tcp_conntrack state; | ||
339 | |||
340 | read_lock_bh(&tcp_lock); | ||
341 | state = conntrack->proto.tcp.state; | ||
342 | read_unlock_bh(&tcp_lock); | ||
343 | |||
344 | return seq_printf(s, "%s ", tcp_conntrack_names[state]); | ||
345 | } | ||
346 | |||
347 | static unsigned int get_conntrack_index(const struct tcphdr *tcph) | ||
348 | { | ||
349 | if (tcph->rst) return TCP_RST_SET; | ||
350 | else if (tcph->syn) return (tcph->ack ? TCP_SYNACK_SET : TCP_SYN_SET); | ||
351 | else if (tcph->fin) return TCP_FIN_SET; | ||
352 | else if (tcph->ack) return TCP_ACK_SET; | ||
353 | else return TCP_NONE_SET; | ||
354 | } | ||
355 | |||
356 | /* TCP connection tracking based on 'Real Stateful TCP Packet Filtering | ||
357 | in IP Filter' by Guido van Rooij. | ||
358 | |||
359 | http://www.nluug.nl/events/sane2000/papers.html | ||
360 | http://www.iae.nl/users/guido/papers/tcp_filtering.ps.gz | ||
361 | |||
362 | The boundaries and the conditions are changed according to RFC793: | ||
363 | the packet must intersect the window (i.e. segments may be | ||
364 | after the right or before the left edge) and thus receivers may ACK | ||
365 | segments after the right edge of the window. | ||
366 | |||
367 | td_maxend = max(sack + max(win,1)) seen in reply packets | ||
368 | td_maxwin = max(max(win, 1)) + (sack - ack) seen in sent packets | ||
369 | td_maxwin += seq + len - sender.td_maxend | ||
370 | if seq + len > sender.td_maxend | ||
371 | td_end = max(seq + len) seen in sent packets | ||
372 | |||
373 | I. Upper bound for valid data: seq <= sender.td_maxend | ||
374 | II. Lower bound for valid data: seq + len >= sender.td_end - receiver.td_maxwin | ||
375 | III. Upper bound for valid ack: sack <= receiver.td_end | ||
376 | IV. Lower bound for valid ack: ack >= receiver.td_end - MAXACKWINDOW | ||
377 | |||
378 | where sack is the highest right edge of sack block found in the packet. | ||
379 | |||
380 | The upper bound limit for a valid ack is not ignored - | ||
381 | we doesn't have to deal with fragments. | ||
382 | */ | ||
383 | |||
384 | static inline __u32 segment_seq_plus_len(__u32 seq, | ||
385 | size_t len, | ||
386 | unsigned int dataoff, | ||
387 | struct tcphdr *tcph) | ||
388 | { | ||
389 | /* XXX Should I use payload length field in IP/IPv6 header ? | ||
390 | * - YK */ | ||
391 | return (seq + len - dataoff - tcph->doff*4 | ||
392 | + (tcph->syn ? 1 : 0) + (tcph->fin ? 1 : 0)); | ||
393 | } | ||
394 | |||
395 | /* Fixme: what about big packets? */ | ||
396 | #define MAXACKWINCONST 66000 | ||
397 | #define MAXACKWINDOW(sender) \ | ||
398 | ((sender)->td_maxwin > MAXACKWINCONST ? (sender)->td_maxwin \ | ||
399 | : MAXACKWINCONST) | ||
400 | |||
401 | /* | ||
402 | * Simplified tcp_parse_options routine from tcp_input.c | ||
403 | */ | ||
404 | static void tcp_options(const struct sk_buff *skb, | ||
405 | unsigned int dataoff, | ||
406 | struct tcphdr *tcph, | ||
407 | struct ip_ct_tcp_state *state) | ||
408 | { | ||
409 | unsigned char buff[(15 * 4) - sizeof(struct tcphdr)]; | ||
410 | unsigned char *ptr; | ||
411 | int length = (tcph->doff*4) - sizeof(struct tcphdr); | ||
412 | |||
413 | if (!length) | ||
414 | return; | ||
415 | |||
416 | ptr = skb_header_pointer(skb, dataoff + sizeof(struct tcphdr), | ||
417 | length, buff); | ||
418 | BUG_ON(ptr == NULL); | ||
419 | |||
420 | state->td_scale = | ||
421 | state->flags = 0; | ||
422 | |||
423 | while (length > 0) { | ||
424 | int opcode=*ptr++; | ||
425 | int opsize; | ||
426 | |||
427 | switch (opcode) { | ||
428 | case TCPOPT_EOL: | ||
429 | return; | ||
430 | case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ | ||
431 | length--; | ||
432 | continue; | ||
433 | default: | ||
434 | opsize=*ptr++; | ||
435 | if (opsize < 2) /* "silly options" */ | ||
436 | return; | ||
437 | if (opsize > length) | ||
438 | break; /* don't parse partial options */ | ||
439 | |||
440 | if (opcode == TCPOPT_SACK_PERM | ||
441 | && opsize == TCPOLEN_SACK_PERM) | ||
442 | state->flags |= IP_CT_TCP_FLAG_SACK_PERM; | ||
443 | else if (opcode == TCPOPT_WINDOW | ||
444 | && opsize == TCPOLEN_WINDOW) { | ||
445 | state->td_scale = *(u_int8_t *)ptr; | ||
446 | |||
447 | if (state->td_scale > 14) { | ||
448 | /* See RFC1323 */ | ||
449 | state->td_scale = 14; | ||
450 | } | ||
451 | state->flags |= | ||
452 | IP_CT_TCP_FLAG_WINDOW_SCALE; | ||
453 | } | ||
454 | ptr += opsize - 2; | ||
455 | length -= opsize; | ||
456 | } | ||
457 | } | ||
458 | } | ||
459 | |||
460 | static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff, | ||
461 | struct tcphdr *tcph, __u32 *sack) | ||
462 | { | ||
463 | unsigned char buff[(15 * 4) - sizeof(struct tcphdr)]; | ||
464 | unsigned char *ptr; | ||
465 | int length = (tcph->doff*4) - sizeof(struct tcphdr); | ||
466 | __u32 tmp; | ||
467 | |||
468 | if (!length) | ||
469 | return; | ||
470 | |||
471 | ptr = skb_header_pointer(skb, dataoff + sizeof(struct tcphdr), | ||
472 | length, buff); | ||
473 | BUG_ON(ptr == NULL); | ||
474 | |||
475 | /* Fast path for timestamp-only option */ | ||
476 | if (length == TCPOLEN_TSTAMP_ALIGNED*4 | ||
477 | && *(__u32 *)ptr == | ||
478 | __constant_ntohl((TCPOPT_NOP << 24) | ||
479 | | (TCPOPT_NOP << 16) | ||
480 | | (TCPOPT_TIMESTAMP << 8) | ||
481 | | TCPOLEN_TIMESTAMP)) | ||
482 | return; | ||
483 | |||
484 | while (length > 0) { | ||
485 | int opcode = *ptr++; | ||
486 | int opsize, i; | ||
487 | |||
488 | switch (opcode) { | ||
489 | case TCPOPT_EOL: | ||
490 | return; | ||
491 | case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ | ||
492 | length--; | ||
493 | continue; | ||
494 | default: | ||
495 | opsize = *ptr++; | ||
496 | if (opsize < 2) /* "silly options" */ | ||
497 | return; | ||
498 | if (opsize > length) | ||
499 | break; /* don't parse partial options */ | ||
500 | |||
501 | if (opcode == TCPOPT_SACK | ||
502 | && opsize >= (TCPOLEN_SACK_BASE | ||
503 | + TCPOLEN_SACK_PERBLOCK) | ||
504 | && !((opsize - TCPOLEN_SACK_BASE) | ||
505 | % TCPOLEN_SACK_PERBLOCK)) { | ||
506 | for (i = 0; | ||
507 | i < (opsize - TCPOLEN_SACK_BASE); | ||
508 | i += TCPOLEN_SACK_PERBLOCK) { | ||
509 | memcpy(&tmp, (__u32 *)(ptr + i) + 1, | ||
510 | sizeof(__u32)); | ||
511 | tmp = ntohl(tmp); | ||
512 | |||
513 | if (after(tmp, *sack)) | ||
514 | *sack = tmp; | ||
515 | } | ||
516 | return; | ||
517 | } | ||
518 | ptr += opsize - 2; | ||
519 | length -= opsize; | ||
520 | } | ||
521 | } | ||
522 | } | ||
523 | |||
524 | static int tcp_in_window(struct ip_ct_tcp *state, | ||
525 | enum ip_conntrack_dir dir, | ||
526 | unsigned int index, | ||
527 | const struct sk_buff *skb, | ||
528 | unsigned int dataoff, | ||
529 | struct tcphdr *tcph, | ||
530 | int pf) | ||
531 | { | ||
532 | struct ip_ct_tcp_state *sender = &state->seen[dir]; | ||
533 | struct ip_ct_tcp_state *receiver = &state->seen[!dir]; | ||
534 | __u32 seq, ack, sack, end, win, swin; | ||
535 | int res; | ||
536 | |||
537 | /* | ||
538 | * Get the required data from the packet. | ||
539 | */ | ||
540 | seq = ntohl(tcph->seq); | ||
541 | ack = sack = ntohl(tcph->ack_seq); | ||
542 | win = ntohs(tcph->window); | ||
543 | end = segment_seq_plus_len(seq, skb->len, dataoff, tcph); | ||
544 | |||
545 | if (receiver->flags & IP_CT_TCP_FLAG_SACK_PERM) | ||
546 | tcp_sack(skb, dataoff, tcph, &sack); | ||
547 | |||
548 | DEBUGP("tcp_in_window: START\n"); | ||
549 | DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu " | ||
550 | "seq=%u ack=%u sack=%u win=%u end=%u\n", | ||
551 | NIPQUAD(iph->saddr), ntohs(tcph->source), | ||
552 | NIPQUAD(iph->daddr), ntohs(tcph->dest), | ||
553 | seq, ack, sack, win, end); | ||
554 | DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i " | ||
555 | "receiver end=%u maxend=%u maxwin=%u scale=%i\n", | ||
556 | sender->td_end, sender->td_maxend, sender->td_maxwin, | ||
557 | sender->td_scale, | ||
558 | receiver->td_end, receiver->td_maxend, receiver->td_maxwin, | ||
559 | receiver->td_scale); | ||
560 | |||
561 | if (sender->td_end == 0) { | ||
562 | /* | ||
563 | * Initialize sender data. | ||
564 | */ | ||
565 | if (tcph->syn && tcph->ack) { | ||
566 | /* | ||
567 | * Outgoing SYN-ACK in reply to a SYN. | ||
568 | */ | ||
569 | sender->td_end = | ||
570 | sender->td_maxend = end; | ||
571 | sender->td_maxwin = (win == 0 ? 1 : win); | ||
572 | |||
573 | tcp_options(skb, dataoff, tcph, sender); | ||
574 | /* | ||
575 | * RFC 1323: | ||
576 | * Both sides must send the Window Scale option | ||
577 | * to enable window scaling in either direction. | ||
578 | */ | ||
579 | if (!(sender->flags & IP_CT_TCP_FLAG_WINDOW_SCALE | ||
580 | && receiver->flags & IP_CT_TCP_FLAG_WINDOW_SCALE)) | ||
581 | sender->td_scale = | ||
582 | receiver->td_scale = 0; | ||
583 | } else { | ||
584 | /* | ||
585 | * We are in the middle of a connection, | ||
586 | * its history is lost for us. | ||
587 | * Let's try to use the data from the packet. | ||
588 | */ | ||
589 | sender->td_end = end; | ||
590 | sender->td_maxwin = (win == 0 ? 1 : win); | ||
591 | sender->td_maxend = end + sender->td_maxwin; | ||
592 | } | ||
593 | } else if (((state->state == TCP_CONNTRACK_SYN_SENT | ||
594 | && dir == IP_CT_DIR_ORIGINAL) | ||
595 | || (state->state == TCP_CONNTRACK_SYN_RECV | ||
596 | && dir == IP_CT_DIR_REPLY)) | ||
597 | && after(end, sender->td_end)) { | ||
598 | /* | ||
599 | * RFC 793: "if a TCP is reinitialized ... then it need | ||
600 | * not wait at all; it must only be sure to use sequence | ||
601 | * numbers larger than those recently used." | ||
602 | */ | ||
603 | sender->td_end = | ||
604 | sender->td_maxend = end; | ||
605 | sender->td_maxwin = (win == 0 ? 1 : win); | ||
606 | |||
607 | tcp_options(skb, dataoff, tcph, sender); | ||
608 | } | ||
609 | |||
610 | if (!(tcph->ack)) { | ||
611 | /* | ||
612 | * If there is no ACK, just pretend it was set and OK. | ||
613 | */ | ||
614 | ack = sack = receiver->td_end; | ||
615 | } else if (((tcp_flag_word(tcph) & (TCP_FLAG_ACK|TCP_FLAG_RST)) == | ||
616 | (TCP_FLAG_ACK|TCP_FLAG_RST)) | ||
617 | && (ack == 0)) { | ||
618 | /* | ||
619 | * Broken TCP stacks, that set ACK in RST packets as well | ||
620 | * with zero ack value. | ||
621 | */ | ||
622 | ack = sack = receiver->td_end; | ||
623 | } | ||
624 | |||
625 | if (seq == end | ||
626 | && (!tcph->rst | ||
627 | || (seq == 0 && state->state == TCP_CONNTRACK_SYN_SENT))) | ||
628 | /* | ||
629 | * Packets contains no data: we assume it is valid | ||
630 | * and check the ack value only. | ||
631 | * However RST segments are always validated by their | ||
632 | * SEQ number, except when seq == 0 (reset sent answering | ||
633 | * SYN. | ||
634 | */ | ||
635 | seq = end = sender->td_end; | ||
636 | |||
637 | DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu " | ||
638 | "seq=%u ack=%u sack =%u win=%u end=%u\n", | ||
639 | NIPQUAD(iph->saddr), ntohs(tcph->source), | ||
640 | NIPQUAD(iph->daddr), ntohs(tcph->dest), | ||
641 | seq, ack, sack, win, end); | ||
642 | DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i " | ||
643 | "receiver end=%u maxend=%u maxwin=%u scale=%i\n", | ||
644 | sender->td_end, sender->td_maxend, sender->td_maxwin, | ||
645 | sender->td_scale, | ||
646 | receiver->td_end, receiver->td_maxend, receiver->td_maxwin, | ||
647 | receiver->td_scale); | ||
648 | |||
649 | DEBUGP("tcp_in_window: I=%i II=%i III=%i IV=%i\n", | ||
650 | before(seq, sender->td_maxend + 1), | ||
651 | after(end, sender->td_end - receiver->td_maxwin - 1), | ||
652 | before(sack, receiver->td_end + 1), | ||
653 | after(ack, receiver->td_end - MAXACKWINDOW(sender))); | ||
654 | |||
655 | if (sender->loose || receiver->loose || | ||
656 | (before(seq, sender->td_maxend + 1) && | ||
657 | after(end, sender->td_end - receiver->td_maxwin - 1) && | ||
658 | before(sack, receiver->td_end + 1) && | ||
659 | after(ack, receiver->td_end - MAXACKWINDOW(sender)))) { | ||
660 | /* | ||
661 | * Take into account window scaling (RFC 1323). | ||
662 | */ | ||
663 | if (!tcph->syn) | ||
664 | win <<= sender->td_scale; | ||
665 | |||
666 | /* | ||
667 | * Update sender data. | ||
668 | */ | ||
669 | swin = win + (sack - ack); | ||
670 | if (sender->td_maxwin < swin) | ||
671 | sender->td_maxwin = swin; | ||
672 | if (after(end, sender->td_end)) | ||
673 | sender->td_end = end; | ||
674 | /* | ||
675 | * Update receiver data. | ||
676 | */ | ||
677 | if (after(end, sender->td_maxend)) | ||
678 | receiver->td_maxwin += end - sender->td_maxend; | ||
679 | if (after(sack + win, receiver->td_maxend - 1)) { | ||
680 | receiver->td_maxend = sack + win; | ||
681 | if (win == 0) | ||
682 | receiver->td_maxend++; | ||
683 | } | ||
684 | |||
685 | /* | ||
686 | * Check retransmissions. | ||
687 | */ | ||
688 | if (index == TCP_ACK_SET) { | ||
689 | if (state->last_dir == dir | ||
690 | && state->last_seq == seq | ||
691 | && state->last_ack == ack | ||
692 | && state->last_end == end) | ||
693 | state->retrans++; | ||
694 | else { | ||
695 | state->last_dir = dir; | ||
696 | state->last_seq = seq; | ||
697 | state->last_ack = ack; | ||
698 | state->last_end = end; | ||
699 | state->retrans = 0; | ||
700 | } | ||
701 | } | ||
702 | /* | ||
703 | * Close the window of disabled window tracking :-) | ||
704 | */ | ||
705 | if (sender->loose) | ||
706 | sender->loose--; | ||
707 | |||
708 | res = 1; | ||
709 | } else { | ||
710 | if (LOG_INVALID(IPPROTO_TCP)) | ||
711 | nf_log_packet(pf, 0, skb, NULL, NULL, NULL, | ||
712 | "nf_ct_tcp: %s ", | ||
713 | before(seq, sender->td_maxend + 1) ? | ||
714 | after(end, sender->td_end - receiver->td_maxwin - 1) ? | ||
715 | before(sack, receiver->td_end + 1) ? | ||
716 | after(ack, receiver->td_end - MAXACKWINDOW(sender)) ? "BUG" | ||
717 | : "ACK is under the lower bound (possible overly delayed ACK)" | ||
718 | : "ACK is over the upper bound (ACKed data not seen yet)" | ||
719 | : "SEQ is under the lower bound (already ACKed data retransmitted)" | ||
720 | : "SEQ is over the upper bound (over the window of the receiver)"); | ||
721 | |||
722 | res = nf_ct_tcp_be_liberal; | ||
723 | } | ||
724 | |||
725 | DEBUGP("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u " | ||
726 | "receiver end=%u maxend=%u maxwin=%u\n", | ||
727 | res, sender->td_end, sender->td_maxend, sender->td_maxwin, | ||
728 | receiver->td_end, receiver->td_maxend, receiver->td_maxwin); | ||
729 | |||
730 | return res; | ||
731 | } | ||
732 | |||
733 | #ifdef CONFIG_IP_NF_NAT_NEEDED | ||
734 | /* Update sender->td_end after NAT successfully mangled the packet */ | ||
735 | /* Caller must linearize skb at tcp header. */ | ||
736 | void nf_conntrack_tcp_update(struct sk_buff *skb, | ||
737 | unsigned int dataoff, | ||
738 | struct nf_conn *conntrack, | ||
739 | int dir) | ||
740 | { | ||
741 | struct tcphdr *tcph = (void *)skb->data + dataoff; | ||
742 | __u32 end; | ||
743 | #ifdef DEBUGP_VARS | ||
744 | struct ip_ct_tcp_state *sender = &conntrack->proto.tcp.seen[dir]; | ||
745 | struct ip_ct_tcp_state *receiver = &conntrack->proto.tcp.seen[!dir]; | ||
746 | #endif | ||
747 | |||
748 | end = segment_seq_plus_len(ntohl(tcph->seq), skb->len, dataoff, tcph); | ||
749 | |||
750 | write_lock_bh(&tcp_lock); | ||
751 | /* | ||
752 | * We have to worry for the ack in the reply packet only... | ||
753 | */ | ||
754 | if (after(end, conntrack->proto.tcp.seen[dir].td_end)) | ||
755 | conntrack->proto.tcp.seen[dir].td_end = end; | ||
756 | conntrack->proto.tcp.last_end = end; | ||
757 | write_unlock_bh(&tcp_lock); | ||
758 | DEBUGP("tcp_update: sender end=%u maxend=%u maxwin=%u scale=%i " | ||
759 | "receiver end=%u maxend=%u maxwin=%u scale=%i\n", | ||
760 | sender->td_end, sender->td_maxend, sender->td_maxwin, | ||
761 | sender->td_scale, | ||
762 | receiver->td_end, receiver->td_maxend, receiver->td_maxwin, | ||
763 | receiver->td_scale); | ||
764 | } | ||
765 | |||
766 | #endif | ||
767 | |||
768 | #define TH_FIN 0x01 | ||
769 | #define TH_SYN 0x02 | ||
770 | #define TH_RST 0x04 | ||
771 | #define TH_PUSH 0x08 | ||
772 | #define TH_ACK 0x10 | ||
773 | #define TH_URG 0x20 | ||
774 | #define TH_ECE 0x40 | ||
775 | #define TH_CWR 0x80 | ||
776 | |||
777 | /* table of valid flag combinations - ECE and CWR are always valid */ | ||
778 | static u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG) + 1] = | ||
779 | { | ||
780 | [TH_SYN] = 1, | ||
781 | [TH_SYN|TH_ACK] = 1, | ||
782 | [TH_SYN|TH_ACK|TH_PUSH] = 1, | ||
783 | [TH_RST] = 1, | ||
784 | [TH_RST|TH_ACK] = 1, | ||
785 | [TH_RST|TH_ACK|TH_PUSH] = 1, | ||
786 | [TH_FIN|TH_ACK] = 1, | ||
787 | [TH_ACK] = 1, | ||
788 | [TH_ACK|TH_PUSH] = 1, | ||
789 | [TH_ACK|TH_URG] = 1, | ||
790 | [TH_ACK|TH_URG|TH_PUSH] = 1, | ||
791 | [TH_FIN|TH_ACK|TH_PUSH] = 1, | ||
792 | [TH_FIN|TH_ACK|TH_URG] = 1, | ||
793 | [TH_FIN|TH_ACK|TH_URG|TH_PUSH] = 1, | ||
794 | }; | ||
795 | |||
796 | /* Protect conntrack agaist broken packets. Code taken from ipt_unclean.c. */ | ||
797 | static int tcp_error(struct sk_buff *skb, | ||
798 | unsigned int dataoff, | ||
799 | enum ip_conntrack_info *ctinfo, | ||
800 | int pf, | ||
801 | unsigned int hooknum, | ||
802 | int(*csum)(const struct sk_buff *,unsigned int)) | ||
803 | { | ||
804 | struct tcphdr _tcph, *th; | ||
805 | unsigned int tcplen = skb->len - dataoff; | ||
806 | u_int8_t tcpflags; | ||
807 | |||
808 | /* Smaller that minimal TCP header? */ | ||
809 | th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph); | ||
810 | if (th == NULL) { | ||
811 | if (LOG_INVALID(IPPROTO_TCP)) | ||
812 | nf_log_packet(pf, 0, skb, NULL, NULL, NULL, | ||
813 | "nf_ct_tcp: short packet "); | ||
814 | return -NF_ACCEPT; | ||
815 | } | ||
816 | |||
817 | /* Not whole TCP header or malformed packet */ | ||
818 | if (th->doff*4 < sizeof(struct tcphdr) || tcplen < th->doff*4) { | ||
819 | if (LOG_INVALID(IPPROTO_TCP)) | ||
820 | nf_log_packet(pf, 0, skb, NULL, NULL, NULL, | ||
821 | "nf_ct_tcp: truncated/malformed packet "); | ||
822 | return -NF_ACCEPT; | ||
823 | } | ||
824 | |||
825 | /* Checksum invalid? Ignore. | ||
826 | * We skip checking packets on the outgoing path | ||
827 | * because the semantic of CHECKSUM_HW is different there | ||
828 | * and moreover root might send raw packets. | ||
829 | */ | ||
830 | /* FIXME: Source route IP option packets --RR */ | ||
831 | if (((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) || | ||
832 | (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING)) | ||
833 | && skb->ip_summed != CHECKSUM_UNNECESSARY | ||
834 | && csum(skb, dataoff)) { | ||
835 | if (LOG_INVALID(IPPROTO_TCP)) | ||
836 | nf_log_packet(pf, 0, skb, NULL, NULL, NULL, | ||
837 | "nf_ct_tcp: bad TCP checksum "); | ||
838 | return -NF_ACCEPT; | ||
839 | } | ||
840 | |||
841 | /* Check TCP flags. */ | ||
842 | tcpflags = (((u_int8_t *)th)[13] & ~(TH_ECE|TH_CWR)); | ||
843 | if (!tcp_valid_flags[tcpflags]) { | ||
844 | if (LOG_INVALID(IPPROTO_TCP)) | ||
845 | nf_log_packet(pf, 0, skb, NULL, NULL, NULL, | ||
846 | "nf_ct_tcp: invalid TCP flag combination "); | ||
847 | return -NF_ACCEPT; | ||
848 | } | ||
849 | |||
850 | return NF_ACCEPT; | ||
851 | } | ||
852 | |||
853 | static int csum4(const struct sk_buff *skb, unsigned int dataoff) | ||
854 | { | ||
855 | return csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr, | ||
856 | skb->len - dataoff, IPPROTO_TCP, | ||
857 | skb->ip_summed == CHECKSUM_HW ? skb->csum | ||
858 | : skb_checksum(skb, dataoff, | ||
859 | skb->len - dataoff, 0)); | ||
860 | } | ||
861 | |||
862 | static int csum6(const struct sk_buff *skb, unsigned int dataoff) | ||
863 | { | ||
864 | return csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr, | ||
865 | skb->len - dataoff, IPPROTO_TCP, | ||
866 | skb->ip_summed == CHECKSUM_HW ? skb->csum | ||
867 | : skb_checksum(skb, dataoff, skb->len - dataoff, | ||
868 | 0)); | ||
869 | } | ||
870 | |||
871 | static int tcp_error4(struct sk_buff *skb, | ||
872 | unsigned int dataoff, | ||
873 | enum ip_conntrack_info *ctinfo, | ||
874 | int pf, | ||
875 | unsigned int hooknum) | ||
876 | { | ||
877 | return tcp_error(skb, dataoff, ctinfo, pf, hooknum, csum4); | ||
878 | } | ||
879 | |||
880 | static int tcp_error6(struct sk_buff *skb, | ||
881 | unsigned int dataoff, | ||
882 | enum ip_conntrack_info *ctinfo, | ||
883 | int pf, | ||
884 | unsigned int hooknum) | ||
885 | { | ||
886 | return tcp_error(skb, dataoff, ctinfo, pf, hooknum, csum6); | ||
887 | } | ||
888 | |||
889 | /* Returns verdict for packet, or -1 for invalid. */ | ||
890 | static int tcp_packet(struct nf_conn *conntrack, | ||
891 | const struct sk_buff *skb, | ||
892 | unsigned int dataoff, | ||
893 | enum ip_conntrack_info ctinfo, | ||
894 | int pf, | ||
895 | unsigned int hooknum) | ||
896 | { | ||
897 | enum tcp_conntrack new_state, old_state; | ||
898 | enum ip_conntrack_dir dir; | ||
899 | struct tcphdr *th, _tcph; | ||
900 | unsigned long timeout; | ||
901 | unsigned int index; | ||
902 | |||
903 | th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph); | ||
904 | BUG_ON(th == NULL); | ||
905 | |||
906 | write_lock_bh(&tcp_lock); | ||
907 | old_state = conntrack->proto.tcp.state; | ||
908 | dir = CTINFO2DIR(ctinfo); | ||
909 | index = get_conntrack_index(th); | ||
910 | new_state = tcp_conntracks[dir][index][old_state]; | ||
911 | |||
912 | switch (new_state) { | ||
913 | case TCP_CONNTRACK_IGNORE: | ||
914 | /* Either SYN in ORIGINAL | ||
915 | * or SYN/ACK in REPLY. */ | ||
916 | if (index == TCP_SYNACK_SET | ||
917 | && conntrack->proto.tcp.last_index == TCP_SYN_SET | ||
918 | && conntrack->proto.tcp.last_dir != dir | ||
919 | && ntohl(th->ack_seq) == | ||
920 | conntrack->proto.tcp.last_end) { | ||
921 | /* This SYN/ACK acknowledges a SYN that we earlier | ||
922 | * ignored as invalid. This means that the client and | ||
923 | * the server are both in sync, while the firewall is | ||
924 | * not. We kill this session and block the SYN/ACK so | ||
925 | * that the client cannot but retransmit its SYN and | ||
926 | * thus initiate a clean new session. | ||
927 | */ | ||
928 | write_unlock_bh(&tcp_lock); | ||
929 | if (LOG_INVALID(IPPROTO_TCP)) | ||
930 | nf_log_packet(pf, 0, skb, NULL, NULL, NULL, | ||
931 | "nf_ct_tcp: killing out of sync session "); | ||
932 | if (del_timer(&conntrack->timeout)) | ||
933 | conntrack->timeout.function((unsigned long) | ||
934 | conntrack); | ||
935 | return -NF_DROP; | ||
936 | } | ||
937 | conntrack->proto.tcp.last_index = index; | ||
938 | conntrack->proto.tcp.last_dir = dir; | ||
939 | conntrack->proto.tcp.last_seq = ntohl(th->seq); | ||
940 | conntrack->proto.tcp.last_end = | ||
941 | segment_seq_plus_len(ntohl(th->seq), skb->len, dataoff, th); | ||
942 | |||
943 | write_unlock_bh(&tcp_lock); | ||
944 | if (LOG_INVALID(IPPROTO_TCP)) | ||
945 | nf_log_packet(pf, 0, skb, NULL, NULL, NULL, | ||
946 | "nf_ct_tcp: invalid packed ignored "); | ||
947 | return NF_ACCEPT; | ||
948 | case TCP_CONNTRACK_MAX: | ||
949 | /* Invalid packet */ | ||
950 | DEBUGP("nf_ct_tcp: Invalid dir=%i index=%u ostate=%u\n", | ||
951 | dir, get_conntrack_index(th), | ||
952 | old_state); | ||
953 | write_unlock_bh(&tcp_lock); | ||
954 | if (LOG_INVALID(IPPROTO_TCP)) | ||
955 | nf_log_packet(pf, 0, skb, NULL, NULL, NULL, | ||
956 | "nf_ct_tcp: invalid state "); | ||
957 | return -NF_ACCEPT; | ||
958 | case TCP_CONNTRACK_SYN_SENT: | ||
959 | if (old_state < TCP_CONNTRACK_TIME_WAIT) | ||
960 | break; | ||
961 | if ((conntrack->proto.tcp.seen[dir].flags & | ||
962 | IP_CT_TCP_FLAG_CLOSE_INIT) | ||
963 | || after(ntohl(th->seq), | ||
964 | conntrack->proto.tcp.seen[dir].td_end)) { | ||
965 | /* Attempt to reopen a closed connection. | ||
966 | * Delete this connection and look up again. */ | ||
967 | write_unlock_bh(&tcp_lock); | ||
968 | if (del_timer(&conntrack->timeout)) | ||
969 | conntrack->timeout.function((unsigned long) | ||
970 | conntrack); | ||
971 | return -NF_REPEAT; | ||
972 | } | ||
973 | case TCP_CONNTRACK_CLOSE: | ||
974 | if (index == TCP_RST_SET | ||
975 | && test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) | ||
976 | && conntrack->proto.tcp.last_index == TCP_SYN_SET | ||
977 | && ntohl(th->ack_seq) == conntrack->proto.tcp.last_end) { | ||
978 | /* RST sent to invalid SYN we had let trough | ||
979 | * SYN was in window then, tear down connection. | ||
980 | * We skip window checking, because packet might ACK | ||
981 | * segments we ignored in the SYN. */ | ||
982 | goto in_window; | ||
983 | } | ||
984 | /* Just fall trough */ | ||
985 | default: | ||
986 | /* Keep compilers happy. */ | ||
987 | break; | ||
988 | } | ||
989 | |||
990 | if (!tcp_in_window(&conntrack->proto.tcp, dir, index, | ||
991 | skb, dataoff, th, pf)) { | ||
992 | write_unlock_bh(&tcp_lock); | ||
993 | return -NF_ACCEPT; | ||
994 | } | ||
995 | in_window: | ||
996 | /* From now on we have got in-window packets */ | ||
997 | conntrack->proto.tcp.last_index = index; | ||
998 | |||
999 | DEBUGP("tcp_conntracks: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu " | ||
1000 | "syn=%i ack=%i fin=%i rst=%i old=%i new=%i\n", | ||
1001 | NIPQUAD(iph->saddr), ntohs(th->source), | ||
1002 | NIPQUAD(iph->daddr), ntohs(th->dest), | ||
1003 | (th->syn ? 1 : 0), (th->ack ? 1 : 0), | ||
1004 | (th->fin ? 1 : 0), (th->rst ? 1 : 0), | ||
1005 | old_state, new_state); | ||
1006 | |||
1007 | conntrack->proto.tcp.state = new_state; | ||
1008 | if (old_state != new_state | ||
1009 | && (new_state == TCP_CONNTRACK_FIN_WAIT | ||
1010 | || new_state == TCP_CONNTRACK_CLOSE)) | ||
1011 | conntrack->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT; | ||
1012 | timeout = conntrack->proto.tcp.retrans >= nf_ct_tcp_max_retrans | ||
1013 | && *tcp_timeouts[new_state] > nf_ct_tcp_timeout_max_retrans | ||
1014 | ? nf_ct_tcp_timeout_max_retrans : *tcp_timeouts[new_state]; | ||
1015 | write_unlock_bh(&tcp_lock); | ||
1016 | |||
1017 | nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb); | ||
1018 | if (new_state != old_state) | ||
1019 | nf_conntrack_event_cache(IPCT_PROTOINFO, skb); | ||
1020 | |||
1021 | if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) { | ||
1022 | /* If only reply is a RST, we can consider ourselves not to | ||
1023 | have an established connection: this is a fairly common | ||
1024 | problem case, so we can delete the conntrack | ||
1025 | immediately. --RR */ | ||
1026 | if (th->rst) { | ||
1027 | if (del_timer(&conntrack->timeout)) | ||
1028 | conntrack->timeout.function((unsigned long) | ||
1029 | conntrack); | ||
1030 | return NF_ACCEPT; | ||
1031 | } | ||
1032 | } else if (!test_bit(IPS_ASSURED_BIT, &conntrack->status) | ||
1033 | && (old_state == TCP_CONNTRACK_SYN_RECV | ||
1034 | || old_state == TCP_CONNTRACK_ESTABLISHED) | ||
1035 | && new_state == TCP_CONNTRACK_ESTABLISHED) { | ||
1036 | /* Set ASSURED if we see see valid ack in ESTABLISHED | ||
1037 | after SYN_RECV or a valid answer for a picked up | ||
1038 | connection. */ | ||
1039 | set_bit(IPS_ASSURED_BIT, &conntrack->status); | ||
1040 | nf_conntrack_event_cache(IPCT_STATUS, skb); | ||
1041 | } | ||
1042 | nf_ct_refresh_acct(conntrack, ctinfo, skb, timeout); | ||
1043 | |||
1044 | return NF_ACCEPT; | ||
1045 | } | ||
1046 | |||
1047 | /* Called when a new connection for this protocol found. */ | ||
1048 | static int tcp_new(struct nf_conn *conntrack, | ||
1049 | const struct sk_buff *skb, | ||
1050 | unsigned int dataoff) | ||
1051 | { | ||
1052 | enum tcp_conntrack new_state; | ||
1053 | struct tcphdr *th, _tcph; | ||
1054 | #ifdef DEBUGP_VARS | ||
1055 | struct ip_ct_tcp_state *sender = &conntrack->proto.tcp.seen[0]; | ||
1056 | struct ip_ct_tcp_state *receiver = &conntrack->proto.tcp.seen[1]; | ||
1057 | #endif | ||
1058 | |||
1059 | th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph); | ||
1060 | BUG_ON(th == NULL); | ||
1061 | |||
1062 | /* Don't need lock here: this conntrack not in circulation yet */ | ||
1063 | new_state | ||
1064 | = tcp_conntracks[0][get_conntrack_index(th)] | ||
1065 | [TCP_CONNTRACK_NONE]; | ||
1066 | |||
1067 | /* Invalid: delete conntrack */ | ||
1068 | if (new_state >= TCP_CONNTRACK_MAX) { | ||
1069 | DEBUGP("nf_ct_tcp: invalid new deleting.\n"); | ||
1070 | return 0; | ||
1071 | } | ||
1072 | |||
1073 | if (new_state == TCP_CONNTRACK_SYN_SENT) { | ||
1074 | /* SYN packet */ | ||
1075 | conntrack->proto.tcp.seen[0].td_end = | ||
1076 | segment_seq_plus_len(ntohl(th->seq), skb->len, | ||
1077 | dataoff, th); | ||
1078 | conntrack->proto.tcp.seen[0].td_maxwin = ntohs(th->window); | ||
1079 | if (conntrack->proto.tcp.seen[0].td_maxwin == 0) | ||
1080 | conntrack->proto.tcp.seen[0].td_maxwin = 1; | ||
1081 | conntrack->proto.tcp.seen[0].td_maxend = | ||
1082 | conntrack->proto.tcp.seen[0].td_end; | ||
1083 | |||
1084 | tcp_options(skb, dataoff, th, &conntrack->proto.tcp.seen[0]); | ||
1085 | conntrack->proto.tcp.seen[1].flags = 0; | ||
1086 | conntrack->proto.tcp.seen[0].loose = | ||
1087 | conntrack->proto.tcp.seen[1].loose = 0; | ||
1088 | } else if (nf_ct_tcp_loose == 0) { | ||
1089 | /* Don't try to pick up connections. */ | ||
1090 | return 0; | ||
1091 | } else { | ||
1092 | /* | ||
1093 | * We are in the middle of a connection, | ||
1094 | * its history is lost for us. | ||
1095 | * Let's try to use the data from the packet. | ||
1096 | */ | ||
1097 | conntrack->proto.tcp.seen[0].td_end = | ||
1098 | segment_seq_plus_len(ntohl(th->seq), skb->len, | ||
1099 | dataoff, th); | ||
1100 | conntrack->proto.tcp.seen[0].td_maxwin = ntohs(th->window); | ||
1101 | if (conntrack->proto.tcp.seen[0].td_maxwin == 0) | ||
1102 | conntrack->proto.tcp.seen[0].td_maxwin = 1; | ||
1103 | conntrack->proto.tcp.seen[0].td_maxend = | ||
1104 | conntrack->proto.tcp.seen[0].td_end + | ||
1105 | conntrack->proto.tcp.seen[0].td_maxwin; | ||
1106 | conntrack->proto.tcp.seen[0].td_scale = 0; | ||
1107 | |||
1108 | /* We assume SACK. Should we assume window scaling too? */ | ||
1109 | conntrack->proto.tcp.seen[0].flags = | ||
1110 | conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM; | ||
1111 | conntrack->proto.tcp.seen[0].loose = | ||
1112 | conntrack->proto.tcp.seen[1].loose = nf_ct_tcp_loose; | ||
1113 | } | ||
1114 | |||
1115 | conntrack->proto.tcp.seen[1].td_end = 0; | ||
1116 | conntrack->proto.tcp.seen[1].td_maxend = 0; | ||
1117 | conntrack->proto.tcp.seen[1].td_maxwin = 1; | ||
1118 | conntrack->proto.tcp.seen[1].td_scale = 0; | ||
1119 | |||
1120 | /* tcp_packet will set them */ | ||
1121 | conntrack->proto.tcp.state = TCP_CONNTRACK_NONE; | ||
1122 | conntrack->proto.tcp.last_index = TCP_NONE_SET; | ||
1123 | |||
1124 | DEBUGP("tcp_new: sender end=%u maxend=%u maxwin=%u scale=%i " | ||
1125 | "receiver end=%u maxend=%u maxwin=%u scale=%i\n", | ||
1126 | sender->td_end, sender->td_maxend, sender->td_maxwin, | ||
1127 | sender->td_scale, | ||
1128 | receiver->td_end, receiver->td_maxend, receiver->td_maxwin, | ||
1129 | receiver->td_scale); | ||
1130 | return 1; | ||
1131 | } | ||
1132 | |||
1133 | struct nf_conntrack_protocol nf_conntrack_protocol_tcp4 = | ||
1134 | { | ||
1135 | .l3proto = PF_INET, | ||
1136 | .proto = IPPROTO_TCP, | ||
1137 | .name = "tcp", | ||
1138 | .pkt_to_tuple = tcp_pkt_to_tuple, | ||
1139 | .invert_tuple = tcp_invert_tuple, | ||
1140 | .print_tuple = tcp_print_tuple, | ||
1141 | .print_conntrack = tcp_print_conntrack, | ||
1142 | .packet = tcp_packet, | ||
1143 | .new = tcp_new, | ||
1144 | .error = tcp_error4, | ||
1145 | }; | ||
1146 | |||
1147 | struct nf_conntrack_protocol nf_conntrack_protocol_tcp6 = | ||
1148 | { | ||
1149 | .l3proto = PF_INET6, | ||
1150 | .proto = IPPROTO_TCP, | ||
1151 | .name = "tcp", | ||
1152 | .pkt_to_tuple = tcp_pkt_to_tuple, | ||
1153 | .invert_tuple = tcp_invert_tuple, | ||
1154 | .print_tuple = tcp_print_tuple, | ||
1155 | .print_conntrack = tcp_print_conntrack, | ||
1156 | .packet = tcp_packet, | ||
1157 | .new = tcp_new, | ||
1158 | .error = tcp_error6, | ||
1159 | }; | ||
1160 | |||
1161 | EXPORT_SYMBOL(nf_conntrack_protocol_tcp4); | ||
1162 | EXPORT_SYMBOL(nf_conntrack_protocol_tcp6); | ||
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c new file mode 100644 index 000000000000..3cae7ce420dd --- /dev/null +++ b/net/netfilter/nf_conntrack_proto_udp.c | |||
@@ -0,0 +1,216 @@ | |||
1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
9 | * - enable working with Layer 3 protocol independent connection tracking. | ||
10 | * | ||
11 | * Derived from net/ipv4/netfilter/ip_conntrack_proto_udp.c | ||
12 | */ | ||
13 | |||
14 | #include <linux/types.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <linux/timer.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/netfilter.h> | ||
19 | #include <linux/udp.h> | ||
20 | #include <linux/seq_file.h> | ||
21 | #include <linux/skbuff.h> | ||
22 | #include <linux/ipv6.h> | ||
23 | #include <net/ip6_checksum.h> | ||
24 | #include <net/checksum.h> | ||
25 | #include <linux/netfilter.h> | ||
26 | #include <linux/netfilter_ipv4.h> | ||
27 | #include <linux/netfilter_ipv6.h> | ||
28 | #include <net/netfilter/nf_conntrack_protocol.h> | ||
29 | |||
30 | unsigned long nf_ct_udp_timeout = 30*HZ; | ||
31 | unsigned long nf_ct_udp_timeout_stream = 180*HZ; | ||
32 | |||
33 | static int udp_pkt_to_tuple(const struct sk_buff *skb, | ||
34 | unsigned int dataoff, | ||
35 | struct nf_conntrack_tuple *tuple) | ||
36 | { | ||
37 | struct udphdr _hdr, *hp; | ||
38 | |||
39 | /* Actually only need first 8 bytes. */ | ||
40 | hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); | ||
41 | if (hp == NULL) | ||
42 | return 0; | ||
43 | |||
44 | tuple->src.u.udp.port = hp->source; | ||
45 | tuple->dst.u.udp.port = hp->dest; | ||
46 | |||
47 | return 1; | ||
48 | } | ||
49 | |||
50 | static int udp_invert_tuple(struct nf_conntrack_tuple *tuple, | ||
51 | const struct nf_conntrack_tuple *orig) | ||
52 | { | ||
53 | tuple->src.u.udp.port = orig->dst.u.udp.port; | ||
54 | tuple->dst.u.udp.port = orig->src.u.udp.port; | ||
55 | return 1; | ||
56 | } | ||
57 | |||
58 | /* Print out the per-protocol part of the tuple. */ | ||
59 | static int udp_print_tuple(struct seq_file *s, | ||
60 | const struct nf_conntrack_tuple *tuple) | ||
61 | { | ||
62 | return seq_printf(s, "sport=%hu dport=%hu ", | ||
63 | ntohs(tuple->src.u.udp.port), | ||
64 | ntohs(tuple->dst.u.udp.port)); | ||
65 | } | ||
66 | |||
67 | /* Print out the private part of the conntrack. */ | ||
68 | static int udp_print_conntrack(struct seq_file *s, | ||
69 | const struct nf_conn *conntrack) | ||
70 | { | ||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | /* Returns verdict for packet, and may modify conntracktype */ | ||
75 | static int udp_packet(struct nf_conn *conntrack, | ||
76 | const struct sk_buff *skb, | ||
77 | unsigned int dataoff, | ||
78 | enum ip_conntrack_info ctinfo, | ||
79 | int pf, | ||
80 | unsigned int hooknum) | ||
81 | { | ||
82 | /* If we've seen traffic both ways, this is some kind of UDP | ||
83 | stream. Extend timeout. */ | ||
84 | if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) { | ||
85 | nf_ct_refresh_acct(conntrack, ctinfo, skb, | ||
86 | nf_ct_udp_timeout_stream); | ||
87 | /* Also, more likely to be important, and not a probe */ | ||
88 | if (!test_and_set_bit(IPS_ASSURED_BIT, &conntrack->status)) | ||
89 | nf_conntrack_event_cache(IPCT_STATUS, skb); | ||
90 | } else | ||
91 | nf_ct_refresh_acct(conntrack, ctinfo, skb, nf_ct_udp_timeout); | ||
92 | |||
93 | return NF_ACCEPT; | ||
94 | } | ||
95 | |||
96 | /* Called when a new connection for this protocol found. */ | ||
97 | static int udp_new(struct nf_conn *conntrack, const struct sk_buff *skb, | ||
98 | unsigned int dataoff) | ||
99 | { | ||
100 | return 1; | ||
101 | } | ||
102 | |||
103 | static int udp_error(struct sk_buff *skb, unsigned int dataoff, | ||
104 | enum ip_conntrack_info *ctinfo, | ||
105 | int pf, | ||
106 | unsigned int hooknum, | ||
107 | int (*csum)(const struct sk_buff *, unsigned int)) | ||
108 | { | ||
109 | unsigned int udplen = skb->len - dataoff; | ||
110 | struct udphdr _hdr, *hdr; | ||
111 | |||
112 | /* Header is too small? */ | ||
113 | hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); | ||
114 | if (hdr == NULL) { | ||
115 | if (LOG_INVALID(IPPROTO_UDP)) | ||
116 | nf_log_packet(pf, 0, skb, NULL, NULL, NULL, | ||
117 | "nf_ct_udp: short packet "); | ||
118 | return -NF_ACCEPT; | ||
119 | } | ||
120 | |||
121 | /* Truncated/malformed packets */ | ||
122 | if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) { | ||
123 | if (LOG_INVALID(IPPROTO_UDP)) | ||
124 | nf_log_packet(pf, 0, skb, NULL, NULL, NULL, | ||
125 | "nf_ct_udp: truncated/malformed packet "); | ||
126 | return -NF_ACCEPT; | ||
127 | } | ||
128 | |||
129 | /* Packet with no checksum */ | ||
130 | if (!hdr->check) | ||
131 | return NF_ACCEPT; | ||
132 | |||
133 | /* Checksum invalid? Ignore. | ||
134 | * We skip checking packets on the outgoing path | ||
135 | * because the semantic of CHECKSUM_HW is different there | ||
136 | * and moreover root might send raw packets. | ||
137 | * FIXME: Source route IP option packets --RR */ | ||
138 | if (((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) || | ||
139 | (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING)) | ||
140 | && skb->ip_summed != CHECKSUM_UNNECESSARY | ||
141 | && csum(skb, dataoff)) { | ||
142 | if (LOG_INVALID(IPPROTO_UDP)) | ||
143 | nf_log_packet(pf, 0, skb, NULL, NULL, NULL, | ||
144 | "nf_ct_udp: bad UDP checksum "); | ||
145 | return -NF_ACCEPT; | ||
146 | } | ||
147 | |||
148 | return NF_ACCEPT; | ||
149 | } | ||
150 | |||
151 | static int csum4(const struct sk_buff *skb, unsigned int dataoff) | ||
152 | { | ||
153 | return csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr, | ||
154 | skb->len - dataoff, IPPROTO_UDP, | ||
155 | skb->ip_summed == CHECKSUM_HW ? skb->csum | ||
156 | : skb_checksum(skb, dataoff, | ||
157 | skb->len - dataoff, 0)); | ||
158 | } | ||
159 | |||
160 | static int csum6(const struct sk_buff *skb, unsigned int dataoff) | ||
161 | { | ||
162 | return csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr, | ||
163 | skb->len - dataoff, IPPROTO_UDP, | ||
164 | skb->ip_summed == CHECKSUM_HW ? skb->csum | ||
165 | : skb_checksum(skb, dataoff, skb->len - dataoff, | ||
166 | 0)); | ||
167 | } | ||
168 | |||
169 | static int udp_error4(struct sk_buff *skb, | ||
170 | unsigned int dataoff, | ||
171 | enum ip_conntrack_info *ctinfo, | ||
172 | int pf, | ||
173 | unsigned int hooknum) | ||
174 | { | ||
175 | return udp_error(skb, dataoff, ctinfo, pf, hooknum, csum4); | ||
176 | } | ||
177 | |||
178 | static int udp_error6(struct sk_buff *skb, | ||
179 | unsigned int dataoff, | ||
180 | enum ip_conntrack_info *ctinfo, | ||
181 | int pf, | ||
182 | unsigned int hooknum) | ||
183 | { | ||
184 | return udp_error(skb, dataoff, ctinfo, pf, hooknum, csum6); | ||
185 | } | ||
186 | |||
187 | struct nf_conntrack_protocol nf_conntrack_protocol_udp4 = | ||
188 | { | ||
189 | .l3proto = PF_INET, | ||
190 | .proto = IPPROTO_UDP, | ||
191 | .name = "udp", | ||
192 | .pkt_to_tuple = udp_pkt_to_tuple, | ||
193 | .invert_tuple = udp_invert_tuple, | ||
194 | .print_tuple = udp_print_tuple, | ||
195 | .print_conntrack = udp_print_conntrack, | ||
196 | .packet = udp_packet, | ||
197 | .new = udp_new, | ||
198 | .error = udp_error4, | ||
199 | }; | ||
200 | |||
201 | struct nf_conntrack_protocol nf_conntrack_protocol_udp6 = | ||
202 | { | ||
203 | .l3proto = PF_INET6, | ||
204 | .proto = IPPROTO_UDP, | ||
205 | .name = "udp", | ||
206 | .pkt_to_tuple = udp_pkt_to_tuple, | ||
207 | .invert_tuple = udp_invert_tuple, | ||
208 | .print_tuple = udp_print_tuple, | ||
209 | .print_conntrack = udp_print_conntrack, | ||
210 | .packet = udp_packet, | ||
211 | .new = udp_new, | ||
212 | .error = udp_error6, | ||
213 | }; | ||
214 | |||
215 | EXPORT_SYMBOL(nf_conntrack_protocol_udp4); | ||
216 | EXPORT_SYMBOL(nf_conntrack_protocol_udp6); | ||
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c new file mode 100644 index 000000000000..45224db4fe2f --- /dev/null +++ b/net/netfilter/nf_conntrack_standalone.c | |||
@@ -0,0 +1,869 @@ | |||
1 | /* This file contains all the functions required for the standalone | ||
2 | nf_conntrack module. | ||
3 | |||
4 | These are not required by the compatibility layer. | ||
5 | */ | ||
6 | |||
7 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
8 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | ||
15 | * - generalize L3 protocol dependent part. | ||
16 | * | ||
17 | * Derived from net/ipv4/netfilter/ip_conntrack_standalone.c | ||
18 | */ | ||
19 | |||
20 | #include <linux/config.h> | ||
21 | #include <linux/types.h> | ||
22 | #include <linux/netfilter.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/skbuff.h> | ||
25 | #include <linux/proc_fs.h> | ||
26 | #include <linux/seq_file.h> | ||
27 | #include <linux/percpu.h> | ||
28 | #include <linux/netdevice.h> | ||
29 | #ifdef CONFIG_SYSCTL | ||
30 | #include <linux/sysctl.h> | ||
31 | #endif | ||
32 | |||
33 | #define ASSERT_READ_LOCK(x) | ||
34 | #define ASSERT_WRITE_LOCK(x) | ||
35 | |||
36 | #include <net/netfilter/nf_conntrack.h> | ||
37 | #include <net/netfilter/nf_conntrack_l3proto.h> | ||
38 | #include <net/netfilter/nf_conntrack_protocol.h> | ||
39 | #include <net/netfilter/nf_conntrack_core.h> | ||
40 | #include <net/netfilter/nf_conntrack_helper.h> | ||
41 | #include <linux/netfilter_ipv4/listhelp.h> | ||
42 | |||
43 | #if 0 | ||
44 | #define DEBUGP printk | ||
45 | #else | ||
46 | #define DEBUGP(format, args...) | ||
47 | #endif | ||
48 | |||
49 | MODULE_LICENSE("GPL"); | ||
50 | |||
51 | extern atomic_t nf_conntrack_count; | ||
52 | DECLARE_PER_CPU(struct ip_conntrack_stat, nf_conntrack_stat); | ||
53 | |||
54 | static int kill_l3proto(struct nf_conn *i, void *data) | ||
55 | { | ||
56 | return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num == | ||
57 | ((struct nf_conntrack_l3proto *)data)->l3proto); | ||
58 | } | ||
59 | |||
60 | static int kill_proto(struct nf_conn *i, void *data) | ||
61 | { | ||
62 | struct nf_conntrack_protocol *proto; | ||
63 | proto = (struct nf_conntrack_protocol *)data; | ||
64 | return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == | ||
65 | proto->proto) && | ||
66 | (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num == | ||
67 | proto->l3proto); | ||
68 | } | ||
69 | |||
70 | #ifdef CONFIG_PROC_FS | ||
71 | static int | ||
72 | print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple, | ||
73 | struct nf_conntrack_l3proto *l3proto, | ||
74 | struct nf_conntrack_protocol *proto) | ||
75 | { | ||
76 | return l3proto->print_tuple(s, tuple) || proto->print_tuple(s, tuple); | ||
77 | } | ||
78 | |||
79 | #ifdef CONFIG_NF_CT_ACCT | ||
80 | static unsigned int | ||
81 | seq_print_counters(struct seq_file *s, | ||
82 | const struct ip_conntrack_counter *counter) | ||
83 | { | ||
84 | return seq_printf(s, "packets=%llu bytes=%llu ", | ||
85 | (unsigned long long)counter->packets, | ||
86 | (unsigned long long)counter->bytes); | ||
87 | } | ||
88 | #else | ||
89 | #define seq_print_counters(x, y) 0 | ||
90 | #endif | ||
91 | |||
92 | struct ct_iter_state { | ||
93 | unsigned int bucket; | ||
94 | }; | ||
95 | |||
96 | static struct list_head *ct_get_first(struct seq_file *seq) | ||
97 | { | ||
98 | struct ct_iter_state *st = seq->private; | ||
99 | |||
100 | for (st->bucket = 0; | ||
101 | st->bucket < nf_conntrack_htable_size; | ||
102 | st->bucket++) { | ||
103 | if (!list_empty(&nf_conntrack_hash[st->bucket])) | ||
104 | return nf_conntrack_hash[st->bucket].next; | ||
105 | } | ||
106 | return NULL; | ||
107 | } | ||
108 | |||
109 | static struct list_head *ct_get_next(struct seq_file *seq, struct list_head *head) | ||
110 | { | ||
111 | struct ct_iter_state *st = seq->private; | ||
112 | |||
113 | head = head->next; | ||
114 | while (head == &nf_conntrack_hash[st->bucket]) { | ||
115 | if (++st->bucket >= nf_conntrack_htable_size) | ||
116 | return NULL; | ||
117 | head = nf_conntrack_hash[st->bucket].next; | ||
118 | } | ||
119 | return head; | ||
120 | } | ||
121 | |||
122 | static struct list_head *ct_get_idx(struct seq_file *seq, loff_t pos) | ||
123 | { | ||
124 | struct list_head *head = ct_get_first(seq); | ||
125 | |||
126 | if (head) | ||
127 | while (pos && (head = ct_get_next(seq, head))) | ||
128 | pos--; | ||
129 | return pos ? NULL : head; | ||
130 | } | ||
131 | |||
132 | static void *ct_seq_start(struct seq_file *seq, loff_t *pos) | ||
133 | { | ||
134 | read_lock_bh(&nf_conntrack_lock); | ||
135 | return ct_get_idx(seq, *pos); | ||
136 | } | ||
137 | |||
138 | static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
139 | { | ||
140 | (*pos)++; | ||
141 | return ct_get_next(s, v); | ||
142 | } | ||
143 | |||
144 | static void ct_seq_stop(struct seq_file *s, void *v) | ||
145 | { | ||
146 | read_unlock_bh(&nf_conntrack_lock); | ||
147 | } | ||
148 | |||
149 | /* return 0 on success, 1 in case of error */ | ||
150 | static int ct_seq_show(struct seq_file *s, void *v) | ||
151 | { | ||
152 | const struct nf_conntrack_tuple_hash *hash = v; | ||
153 | const struct nf_conn *conntrack = nf_ct_tuplehash_to_ctrack(hash); | ||
154 | struct nf_conntrack_l3proto *l3proto; | ||
155 | struct nf_conntrack_protocol *proto; | ||
156 | |||
157 | ASSERT_READ_LOCK(&nf_conntrack_lock); | ||
158 | NF_CT_ASSERT(conntrack); | ||
159 | |||
160 | /* we only want to print DIR_ORIGINAL */ | ||
161 | if (NF_CT_DIRECTION(hash)) | ||
162 | return 0; | ||
163 | |||
164 | l3proto = nf_ct_find_l3proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL] | ||
165 | .tuple.src.l3num); | ||
166 | |||
167 | NF_CT_ASSERT(l3proto); | ||
168 | proto = nf_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL] | ||
169 | .tuple.src.l3num, | ||
170 | conntrack->tuplehash[IP_CT_DIR_ORIGINAL] | ||
171 | .tuple.dst.protonum); | ||
172 | NF_CT_ASSERT(proto); | ||
173 | |||
174 | if (seq_printf(s, "%-8s %u %-8s %u %ld ", | ||
175 | l3proto->name, | ||
176 | conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num, | ||
177 | proto->name, | ||
178 | conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum, | ||
179 | timer_pending(&conntrack->timeout) | ||
180 | ? (long)(conntrack->timeout.expires - jiffies)/HZ : 0) != 0) | ||
181 | return -ENOSPC; | ||
182 | |||
183 | if (l3proto->print_conntrack(s, conntrack)) | ||
184 | return -ENOSPC; | ||
185 | |||
186 | if (proto->print_conntrack(s, conntrack)) | ||
187 | return -ENOSPC; | ||
188 | |||
189 | if (print_tuple(s, &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple, | ||
190 | l3proto, proto)) | ||
191 | return -ENOSPC; | ||
192 | |||
193 | if (seq_print_counters(s, &conntrack->counters[IP_CT_DIR_ORIGINAL])) | ||
194 | return -ENOSPC; | ||
195 | |||
196 | if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status))) | ||
197 | if (seq_printf(s, "[UNREPLIED] ")) | ||
198 | return -ENOSPC; | ||
199 | |||
200 | if (print_tuple(s, &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple, | ||
201 | l3proto, proto)) | ||
202 | return -ENOSPC; | ||
203 | |||
204 | if (seq_print_counters(s, &conntrack->counters[IP_CT_DIR_REPLY])) | ||
205 | return -ENOSPC; | ||
206 | |||
207 | if (test_bit(IPS_ASSURED_BIT, &conntrack->status)) | ||
208 | if (seq_printf(s, "[ASSURED] ")) | ||
209 | return -ENOSPC; | ||
210 | |||
211 | #if defined(CONFIG_NF_CONNTRACK_MARK) | ||
212 | if (seq_printf(s, "mark=%u ", conntrack->mark)) | ||
213 | return -ENOSPC; | ||
214 | #endif | ||
215 | |||
216 | if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use))) | ||
217 | return -ENOSPC; | ||
218 | |||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | static struct seq_operations ct_seq_ops = { | ||
223 | .start = ct_seq_start, | ||
224 | .next = ct_seq_next, | ||
225 | .stop = ct_seq_stop, | ||
226 | .show = ct_seq_show | ||
227 | }; | ||
228 | |||
229 | static int ct_open(struct inode *inode, struct file *file) | ||
230 | { | ||
231 | struct seq_file *seq; | ||
232 | struct ct_iter_state *st; | ||
233 | int ret; | ||
234 | |||
235 | st = kmalloc(sizeof(struct ct_iter_state), GFP_KERNEL); | ||
236 | if (st == NULL) | ||
237 | return -ENOMEM; | ||
238 | ret = seq_open(file, &ct_seq_ops); | ||
239 | if (ret) | ||
240 | goto out_free; | ||
241 | seq = file->private_data; | ||
242 | seq->private = st; | ||
243 | memset(st, 0, sizeof(struct ct_iter_state)); | ||
244 | return ret; | ||
245 | out_free: | ||
246 | kfree(st); | ||
247 | return ret; | ||
248 | } | ||
249 | |||
250 | static struct file_operations ct_file_ops = { | ||
251 | .owner = THIS_MODULE, | ||
252 | .open = ct_open, | ||
253 | .read = seq_read, | ||
254 | .llseek = seq_lseek, | ||
255 | .release = seq_release_private, | ||
256 | }; | ||
257 | |||
258 | /* expects */ | ||
259 | static void *exp_seq_start(struct seq_file *s, loff_t *pos) | ||
260 | { | ||
261 | struct list_head *e = &nf_conntrack_expect_list; | ||
262 | loff_t i; | ||
263 | |||
264 | /* strange seq_file api calls stop even if we fail, | ||
265 | * thus we need to grab lock since stop unlocks */ | ||
266 | read_lock_bh(&nf_conntrack_lock); | ||
267 | |||
268 | if (list_empty(e)) | ||
269 | return NULL; | ||
270 | |||
271 | for (i = 0; i <= *pos; i++) { | ||
272 | e = e->next; | ||
273 | if (e == &nf_conntrack_expect_list) | ||
274 | return NULL; | ||
275 | } | ||
276 | return e; | ||
277 | } | ||
278 | |||
279 | static void *exp_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
280 | { | ||
281 | struct list_head *e = v; | ||
282 | |||
283 | ++*pos; | ||
284 | e = e->next; | ||
285 | |||
286 | if (e == &nf_conntrack_expect_list) | ||
287 | return NULL; | ||
288 | |||
289 | return e; | ||
290 | } | ||
291 | |||
292 | static void exp_seq_stop(struct seq_file *s, void *v) | ||
293 | { | ||
294 | read_unlock_bh(&nf_conntrack_lock); | ||
295 | } | ||
296 | |||
297 | static int exp_seq_show(struct seq_file *s, void *v) | ||
298 | { | ||
299 | struct nf_conntrack_expect *expect = v; | ||
300 | |||
301 | if (expect->timeout.function) | ||
302 | seq_printf(s, "%ld ", timer_pending(&expect->timeout) | ||
303 | ? (long)(expect->timeout.expires - jiffies)/HZ : 0); | ||
304 | else | ||
305 | seq_printf(s, "- "); | ||
306 | seq_printf(s, "l3proto = %u proto=%u ", | ||
307 | expect->tuple.src.l3num, | ||
308 | expect->tuple.dst.protonum); | ||
309 | print_tuple(s, &expect->tuple, | ||
310 | nf_ct_find_l3proto(expect->tuple.src.l3num), | ||
311 | nf_ct_find_proto(expect->tuple.src.l3num, | ||
312 | expect->tuple.dst.protonum)); | ||
313 | return seq_putc(s, '\n'); | ||
314 | } | ||
315 | |||
316 | static struct seq_operations exp_seq_ops = { | ||
317 | .start = exp_seq_start, | ||
318 | .next = exp_seq_next, | ||
319 | .stop = exp_seq_stop, | ||
320 | .show = exp_seq_show | ||
321 | }; | ||
322 | |||
323 | static int exp_open(struct inode *inode, struct file *file) | ||
324 | { | ||
325 | return seq_open(file, &exp_seq_ops); | ||
326 | } | ||
327 | |||
328 | static struct file_operations exp_file_ops = { | ||
329 | .owner = THIS_MODULE, | ||
330 | .open = exp_open, | ||
331 | .read = seq_read, | ||
332 | .llseek = seq_lseek, | ||
333 | .release = seq_release | ||
334 | }; | ||
335 | |||
336 | static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos) | ||
337 | { | ||
338 | int cpu; | ||
339 | |||
340 | if (*pos == 0) | ||
341 | return SEQ_START_TOKEN; | ||
342 | |||
343 | for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) { | ||
344 | if (!cpu_possible(cpu)) | ||
345 | continue; | ||
346 | *pos = cpu + 1; | ||
347 | return &per_cpu(nf_conntrack_stat, cpu); | ||
348 | } | ||
349 | |||
350 | return NULL; | ||
351 | } | ||
352 | |||
353 | static void *ct_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
354 | { | ||
355 | int cpu; | ||
356 | |||
357 | for (cpu = *pos; cpu < NR_CPUS; ++cpu) { | ||
358 | if (!cpu_possible(cpu)) | ||
359 | continue; | ||
360 | *pos = cpu + 1; | ||
361 | return &per_cpu(nf_conntrack_stat, cpu); | ||
362 | } | ||
363 | |||
364 | return NULL; | ||
365 | } | ||
366 | |||
367 | static void ct_cpu_seq_stop(struct seq_file *seq, void *v) | ||
368 | { | ||
369 | } | ||
370 | |||
371 | static int ct_cpu_seq_show(struct seq_file *seq, void *v) | ||
372 | { | ||
373 | unsigned int nr_conntracks = atomic_read(&nf_conntrack_count); | ||
374 | struct ip_conntrack_stat *st = v; | ||
375 | |||
376 | if (v == SEQ_START_TOKEN) { | ||
377 | seq_printf(seq, "entries searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error expect_new expect_create expect_delete\n"); | ||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x " | ||
382 | "%08x %08x %08x %08x %08x %08x %08x %08x \n", | ||
383 | nr_conntracks, | ||
384 | st->searched, | ||
385 | st->found, | ||
386 | st->new, | ||
387 | st->invalid, | ||
388 | st->ignore, | ||
389 | st->delete, | ||
390 | st->delete_list, | ||
391 | st->insert, | ||
392 | st->insert_failed, | ||
393 | st->drop, | ||
394 | st->early_drop, | ||
395 | st->error, | ||
396 | |||
397 | st->expect_new, | ||
398 | st->expect_create, | ||
399 | st->expect_delete | ||
400 | ); | ||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | static struct seq_operations ct_cpu_seq_ops = { | ||
405 | .start = ct_cpu_seq_start, | ||
406 | .next = ct_cpu_seq_next, | ||
407 | .stop = ct_cpu_seq_stop, | ||
408 | .show = ct_cpu_seq_show, | ||
409 | }; | ||
410 | |||
411 | static int ct_cpu_seq_open(struct inode *inode, struct file *file) | ||
412 | { | ||
413 | return seq_open(file, &ct_cpu_seq_ops); | ||
414 | } | ||
415 | |||
416 | static struct file_operations ct_cpu_seq_fops = { | ||
417 | .owner = THIS_MODULE, | ||
418 | .open = ct_cpu_seq_open, | ||
419 | .read = seq_read, | ||
420 | .llseek = seq_lseek, | ||
421 | .release = seq_release_private, | ||
422 | }; | ||
423 | #endif /* CONFIG_PROC_FS */ | ||
424 | |||
425 | /* Sysctl support */ | ||
426 | |||
427 | #ifdef CONFIG_SYSCTL | ||
428 | |||
429 | /* From nf_conntrack_core.c */ | ||
430 | extern int nf_conntrack_max; | ||
431 | extern unsigned int nf_conntrack_htable_size; | ||
432 | |||
433 | /* From nf_conntrack_proto_tcp.c */ | ||
434 | extern unsigned long nf_ct_tcp_timeout_syn_sent; | ||
435 | extern unsigned long nf_ct_tcp_timeout_syn_recv; | ||
436 | extern unsigned long nf_ct_tcp_timeout_established; | ||
437 | extern unsigned long nf_ct_tcp_timeout_fin_wait; | ||
438 | extern unsigned long nf_ct_tcp_timeout_close_wait; | ||
439 | extern unsigned long nf_ct_tcp_timeout_last_ack; | ||
440 | extern unsigned long nf_ct_tcp_timeout_time_wait; | ||
441 | extern unsigned long nf_ct_tcp_timeout_close; | ||
442 | extern unsigned long nf_ct_tcp_timeout_max_retrans; | ||
443 | extern int nf_ct_tcp_loose; | ||
444 | extern int nf_ct_tcp_be_liberal; | ||
445 | extern int nf_ct_tcp_max_retrans; | ||
446 | |||
447 | /* From nf_conntrack_proto_udp.c */ | ||
448 | extern unsigned long nf_ct_udp_timeout; | ||
449 | extern unsigned long nf_ct_udp_timeout_stream; | ||
450 | |||
451 | /* From nf_conntrack_proto_generic.c */ | ||
452 | extern unsigned long nf_ct_generic_timeout; | ||
453 | |||
454 | /* Log invalid packets of a given protocol */ | ||
455 | static int log_invalid_proto_min = 0; | ||
456 | static int log_invalid_proto_max = 255; | ||
457 | |||
458 | static struct ctl_table_header *nf_ct_sysctl_header; | ||
459 | |||
460 | static ctl_table nf_ct_sysctl_table[] = { | ||
461 | { | ||
462 | .ctl_name = NET_NF_CONNTRACK_MAX, | ||
463 | .procname = "nf_conntrack_max", | ||
464 | .data = &nf_conntrack_max, | ||
465 | .maxlen = sizeof(int), | ||
466 | .mode = 0644, | ||
467 | .proc_handler = &proc_dointvec, | ||
468 | }, | ||
469 | { | ||
470 | .ctl_name = NET_NF_CONNTRACK_COUNT, | ||
471 | .procname = "nf_conntrack_count", | ||
472 | .data = &nf_conntrack_count, | ||
473 | .maxlen = sizeof(int), | ||
474 | .mode = 0444, | ||
475 | .proc_handler = &proc_dointvec, | ||
476 | }, | ||
477 | { | ||
478 | .ctl_name = NET_NF_CONNTRACK_BUCKETS, | ||
479 | .procname = "nf_conntrack_buckets", | ||
480 | .data = &nf_conntrack_htable_size, | ||
481 | .maxlen = sizeof(unsigned int), | ||
482 | .mode = 0444, | ||
483 | .proc_handler = &proc_dointvec, | ||
484 | }, | ||
485 | { | ||
486 | .ctl_name = NET_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT, | ||
487 | .procname = "nf_conntrack_tcp_timeout_syn_sent", | ||
488 | .data = &nf_ct_tcp_timeout_syn_sent, | ||
489 | .maxlen = sizeof(unsigned int), | ||
490 | .mode = 0644, | ||
491 | .proc_handler = &proc_dointvec_jiffies, | ||
492 | }, | ||
493 | { | ||
494 | .ctl_name = NET_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV, | ||
495 | .procname = "nf_conntrack_tcp_timeout_syn_recv", | ||
496 | .data = &nf_ct_tcp_timeout_syn_recv, | ||
497 | .maxlen = sizeof(unsigned int), | ||
498 | .mode = 0644, | ||
499 | .proc_handler = &proc_dointvec_jiffies, | ||
500 | }, | ||
501 | { | ||
502 | .ctl_name = NET_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED, | ||
503 | .procname = "nf_conntrack_tcp_timeout_established", | ||
504 | .data = &nf_ct_tcp_timeout_established, | ||
505 | .maxlen = sizeof(unsigned int), | ||
506 | .mode = 0644, | ||
507 | .proc_handler = &proc_dointvec_jiffies, | ||
508 | }, | ||
509 | { | ||
510 | .ctl_name = NET_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT, | ||
511 | .procname = "nf_conntrack_tcp_timeout_fin_wait", | ||
512 | .data = &nf_ct_tcp_timeout_fin_wait, | ||
513 | .maxlen = sizeof(unsigned int), | ||
514 | .mode = 0644, | ||
515 | .proc_handler = &proc_dointvec_jiffies, | ||
516 | }, | ||
517 | { | ||
518 | .ctl_name = NET_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT, | ||
519 | .procname = "nf_conntrack_tcp_timeout_close_wait", | ||
520 | .data = &nf_ct_tcp_timeout_close_wait, | ||
521 | .maxlen = sizeof(unsigned int), | ||
522 | .mode = 0644, | ||
523 | .proc_handler = &proc_dointvec_jiffies, | ||
524 | }, | ||
525 | { | ||
526 | .ctl_name = NET_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK, | ||
527 | .procname = "nf_conntrack_tcp_timeout_last_ack", | ||
528 | .data = &nf_ct_tcp_timeout_last_ack, | ||
529 | .maxlen = sizeof(unsigned int), | ||
530 | .mode = 0644, | ||
531 | .proc_handler = &proc_dointvec_jiffies, | ||
532 | }, | ||
533 | { | ||
534 | .ctl_name = NET_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT, | ||
535 | .procname = "nf_conntrack_tcp_timeout_time_wait", | ||
536 | .data = &nf_ct_tcp_timeout_time_wait, | ||
537 | .maxlen = sizeof(unsigned int), | ||
538 | .mode = 0644, | ||
539 | .proc_handler = &proc_dointvec_jiffies, | ||
540 | }, | ||
541 | { | ||
542 | .ctl_name = NET_NF_CONNTRACK_TCP_TIMEOUT_CLOSE, | ||
543 | .procname = "nf_conntrack_tcp_timeout_close", | ||
544 | .data = &nf_ct_tcp_timeout_close, | ||
545 | .maxlen = sizeof(unsigned int), | ||
546 | .mode = 0644, | ||
547 | .proc_handler = &proc_dointvec_jiffies, | ||
548 | }, | ||
549 | { | ||
550 | .ctl_name = NET_NF_CONNTRACK_UDP_TIMEOUT, | ||
551 | .procname = "nf_conntrack_udp_timeout", | ||
552 | .data = &nf_ct_udp_timeout, | ||
553 | .maxlen = sizeof(unsigned int), | ||
554 | .mode = 0644, | ||
555 | .proc_handler = &proc_dointvec_jiffies, | ||
556 | }, | ||
557 | { | ||
558 | .ctl_name = NET_NF_CONNTRACK_UDP_TIMEOUT_STREAM, | ||
559 | .procname = "nf_conntrack_udp_timeout_stream", | ||
560 | .data = &nf_ct_udp_timeout_stream, | ||
561 | .maxlen = sizeof(unsigned int), | ||
562 | .mode = 0644, | ||
563 | .proc_handler = &proc_dointvec_jiffies, | ||
564 | }, | ||
565 | { | ||
566 | .ctl_name = NET_NF_CONNTRACK_GENERIC_TIMEOUT, | ||
567 | .procname = "nf_conntrack_generic_timeout", | ||
568 | .data = &nf_ct_generic_timeout, | ||
569 | .maxlen = sizeof(unsigned int), | ||
570 | .mode = 0644, | ||
571 | .proc_handler = &proc_dointvec_jiffies, | ||
572 | }, | ||
573 | { | ||
574 | .ctl_name = NET_NF_CONNTRACK_LOG_INVALID, | ||
575 | .procname = "nf_conntrack_log_invalid", | ||
576 | .data = &nf_ct_log_invalid, | ||
577 | .maxlen = sizeof(unsigned int), | ||
578 | .mode = 0644, | ||
579 | .proc_handler = &proc_dointvec_minmax, | ||
580 | .strategy = &sysctl_intvec, | ||
581 | .extra1 = &log_invalid_proto_min, | ||
582 | .extra2 = &log_invalid_proto_max, | ||
583 | }, | ||
584 | { | ||
585 | .ctl_name = NET_NF_CONNTRACK_TCP_TIMEOUT_MAX_RETRANS, | ||
586 | .procname = "nf_conntrack_tcp_timeout_max_retrans", | ||
587 | .data = &nf_ct_tcp_timeout_max_retrans, | ||
588 | .maxlen = sizeof(unsigned int), | ||
589 | .mode = 0644, | ||
590 | .proc_handler = &proc_dointvec_jiffies, | ||
591 | }, | ||
592 | { | ||
593 | .ctl_name = NET_NF_CONNTRACK_TCP_LOOSE, | ||
594 | .procname = "nf_conntrack_tcp_loose", | ||
595 | .data = &nf_ct_tcp_loose, | ||
596 | .maxlen = sizeof(unsigned int), | ||
597 | .mode = 0644, | ||
598 | .proc_handler = &proc_dointvec, | ||
599 | }, | ||
600 | { | ||
601 | .ctl_name = NET_NF_CONNTRACK_TCP_BE_LIBERAL, | ||
602 | .procname = "nf_conntrack_tcp_be_liberal", | ||
603 | .data = &nf_ct_tcp_be_liberal, | ||
604 | .maxlen = sizeof(unsigned int), | ||
605 | .mode = 0644, | ||
606 | .proc_handler = &proc_dointvec, | ||
607 | }, | ||
608 | { | ||
609 | .ctl_name = NET_NF_CONNTRACK_TCP_MAX_RETRANS, | ||
610 | .procname = "nf_conntrack_tcp_max_retrans", | ||
611 | .data = &nf_ct_tcp_max_retrans, | ||
612 | .maxlen = sizeof(unsigned int), | ||
613 | .mode = 0644, | ||
614 | .proc_handler = &proc_dointvec, | ||
615 | }, | ||
616 | |||
617 | { .ctl_name = 0 } | ||
618 | }; | ||
619 | |||
620 | #define NET_NF_CONNTRACK_MAX 2089 | ||
621 | |||
622 | static ctl_table nf_ct_netfilter_table[] = { | ||
623 | { | ||
624 | .ctl_name = NET_NETFILTER, | ||
625 | .procname = "netfilter", | ||
626 | .mode = 0555, | ||
627 | .child = nf_ct_sysctl_table, | ||
628 | }, | ||
629 | { | ||
630 | .ctl_name = NET_NF_CONNTRACK_MAX, | ||
631 | .procname = "nf_conntrack_max", | ||
632 | .data = &nf_conntrack_max, | ||
633 | .maxlen = sizeof(int), | ||
634 | .mode = 0644, | ||
635 | .proc_handler = &proc_dointvec, | ||
636 | }, | ||
637 | { .ctl_name = 0 } | ||
638 | }; | ||
639 | |||
640 | static ctl_table nf_ct_net_table[] = { | ||
641 | { | ||
642 | .ctl_name = CTL_NET, | ||
643 | .procname = "net", | ||
644 | .mode = 0555, | ||
645 | .child = nf_ct_netfilter_table, | ||
646 | }, | ||
647 | { .ctl_name = 0 } | ||
648 | }; | ||
649 | EXPORT_SYMBOL(nf_ct_log_invalid); | ||
650 | #endif /* CONFIG_SYSCTL */ | ||
651 | |||
652 | static int init_or_cleanup(int init) | ||
653 | { | ||
654 | #ifdef CONFIG_PROC_FS | ||
655 | struct proc_dir_entry *proc, *proc_exp, *proc_stat; | ||
656 | #endif | ||
657 | int ret = 0; | ||
658 | |||
659 | if (!init) goto cleanup; | ||
660 | |||
661 | ret = nf_conntrack_init(); | ||
662 | if (ret < 0) | ||
663 | goto cleanup_nothing; | ||
664 | |||
665 | #ifdef CONFIG_PROC_FS | ||
666 | proc = proc_net_fops_create("nf_conntrack", 0440, &ct_file_ops); | ||
667 | if (!proc) goto cleanup_init; | ||
668 | |||
669 | proc_exp = proc_net_fops_create("nf_conntrack_expect", 0440, | ||
670 | &exp_file_ops); | ||
671 | if (!proc_exp) goto cleanup_proc; | ||
672 | |||
673 | proc_stat = create_proc_entry("nf_conntrack", S_IRUGO, proc_net_stat); | ||
674 | if (!proc_stat) | ||
675 | goto cleanup_proc_exp; | ||
676 | |||
677 | proc_stat->proc_fops = &ct_cpu_seq_fops; | ||
678 | proc_stat->owner = THIS_MODULE; | ||
679 | #endif | ||
680 | #ifdef CONFIG_SYSCTL | ||
681 | nf_ct_sysctl_header = register_sysctl_table(nf_ct_net_table, 0); | ||
682 | if (nf_ct_sysctl_header == NULL) { | ||
683 | printk("nf_conntrack: can't register to sysctl.\n"); | ||
684 | ret = -ENOMEM; | ||
685 | goto cleanup_proc_stat; | ||
686 | } | ||
687 | #endif | ||
688 | |||
689 | return ret; | ||
690 | |||
691 | cleanup: | ||
692 | #ifdef CONFIG_SYSCTL | ||
693 | unregister_sysctl_table(nf_ct_sysctl_header); | ||
694 | cleanup_proc_stat: | ||
695 | #endif | ||
696 | #ifdef CONFIG_PROC_FS | ||
697 | proc_net_remove("nf_conntrack_stat"); | ||
698 | cleanup_proc_exp: | ||
699 | proc_net_remove("nf_conntrack_expect"); | ||
700 | cleanup_proc: | ||
701 | proc_net_remove("nf_conntrack"); | ||
702 | cleanup_init: | ||
703 | #endif /* CNFIG_PROC_FS */ | ||
704 | nf_conntrack_cleanup(); | ||
705 | cleanup_nothing: | ||
706 | return ret; | ||
707 | } | ||
708 | |||
709 | int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto) | ||
710 | { | ||
711 | int ret = 0; | ||
712 | |||
713 | write_lock_bh(&nf_conntrack_lock); | ||
714 | if (nf_ct_l3protos[proto->l3proto] != &nf_conntrack_generic_l3proto) { | ||
715 | ret = -EBUSY; | ||
716 | goto out; | ||
717 | } | ||
718 | nf_ct_l3protos[proto->l3proto] = proto; | ||
719 | out: | ||
720 | write_unlock_bh(&nf_conntrack_lock); | ||
721 | |||
722 | return ret; | ||
723 | } | ||
724 | |||
725 | void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto) | ||
726 | { | ||
727 | write_lock_bh(&nf_conntrack_lock); | ||
728 | nf_ct_l3protos[proto->l3proto] = &nf_conntrack_generic_l3proto; | ||
729 | write_unlock_bh(&nf_conntrack_lock); | ||
730 | |||
731 | /* Somebody could be still looking at the proto in bh. */ | ||
732 | synchronize_net(); | ||
733 | |||
734 | /* Remove all contrack entries for this protocol */ | ||
735 | nf_ct_iterate_cleanup(kill_l3proto, proto); | ||
736 | } | ||
737 | |||
738 | /* FIXME: Allow NULL functions and sub in pointers to generic for | ||
739 | them. --RR */ | ||
740 | int nf_conntrack_protocol_register(struct nf_conntrack_protocol *proto) | ||
741 | { | ||
742 | int ret = 0; | ||
743 | |||
744 | retry: | ||
745 | write_lock_bh(&nf_conntrack_lock); | ||
746 | if (nf_ct_protos[proto->l3proto]) { | ||
747 | if (nf_ct_protos[proto->l3proto][proto->proto] | ||
748 | != &nf_conntrack_generic_protocol) { | ||
749 | ret = -EBUSY; | ||
750 | goto out_unlock; | ||
751 | } | ||
752 | } else { | ||
753 | /* l3proto may be loaded latter. */ | ||
754 | struct nf_conntrack_protocol **proto_array; | ||
755 | int i; | ||
756 | |||
757 | write_unlock_bh(&nf_conntrack_lock); | ||
758 | |||
759 | proto_array = (struct nf_conntrack_protocol **) | ||
760 | kmalloc(MAX_NF_CT_PROTO * | ||
761 | sizeof(struct nf_conntrack_protocol *), | ||
762 | GFP_KERNEL); | ||
763 | if (proto_array == NULL) { | ||
764 | ret = -ENOMEM; | ||
765 | goto out; | ||
766 | } | ||
767 | for (i = 0; i < MAX_NF_CT_PROTO; i++) | ||
768 | proto_array[i] = &nf_conntrack_generic_protocol; | ||
769 | |||
770 | write_lock_bh(&nf_conntrack_lock); | ||
771 | if (nf_ct_protos[proto->l3proto]) { | ||
772 | /* bad timing, but no problem */ | ||
773 | write_unlock_bh(&nf_conntrack_lock); | ||
774 | kfree(proto_array); | ||
775 | } else { | ||
776 | nf_ct_protos[proto->l3proto] = proto_array; | ||
777 | write_unlock_bh(&nf_conntrack_lock); | ||
778 | } | ||
779 | |||
780 | /* | ||
781 | * Just once because array is never freed until unloading | ||
782 | * nf_conntrack.ko | ||
783 | */ | ||
784 | goto retry; | ||
785 | } | ||
786 | |||
787 | nf_ct_protos[proto->l3proto][proto->proto] = proto; | ||
788 | |||
789 | out_unlock: | ||
790 | write_unlock_bh(&nf_conntrack_lock); | ||
791 | out: | ||
792 | return ret; | ||
793 | } | ||
794 | |||
795 | void nf_conntrack_protocol_unregister(struct nf_conntrack_protocol *proto) | ||
796 | { | ||
797 | write_lock_bh(&nf_conntrack_lock); | ||
798 | nf_ct_protos[proto->l3proto][proto->proto] | ||
799 | = &nf_conntrack_generic_protocol; | ||
800 | write_unlock_bh(&nf_conntrack_lock); | ||
801 | |||
802 | /* Somebody could be still looking at the proto in bh. */ | ||
803 | synchronize_net(); | ||
804 | |||
805 | /* Remove all contrack entries for this protocol */ | ||
806 | nf_ct_iterate_cleanup(kill_proto, proto); | ||
807 | } | ||
808 | |||
809 | static int __init init(void) | ||
810 | { | ||
811 | return init_or_cleanup(1); | ||
812 | } | ||
813 | |||
814 | static void __exit fini(void) | ||
815 | { | ||
816 | init_or_cleanup(0); | ||
817 | } | ||
818 | |||
819 | module_init(init); | ||
820 | module_exit(fini); | ||
821 | |||
822 | /* Some modules need us, but don't depend directly on any symbol. | ||
823 | They should call this. */ | ||
824 | void need_nf_conntrack(void) | ||
825 | { | ||
826 | } | ||
827 | |||
828 | #ifdef CONFIG_NF_CONNTRACK_EVENTS | ||
829 | EXPORT_SYMBOL_GPL(nf_conntrack_chain); | ||
830 | EXPORT_SYMBOL_GPL(nf_conntrack_expect_chain); | ||
831 | EXPORT_SYMBOL_GPL(nf_conntrack_register_notifier); | ||
832 | EXPORT_SYMBOL_GPL(nf_conntrack_unregister_notifier); | ||
833 | EXPORT_SYMBOL_GPL(__nf_ct_event_cache_init); | ||
834 | EXPORT_PER_CPU_SYMBOL_GPL(nf_conntrack_ecache); | ||
835 | EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events); | ||
836 | #endif | ||
837 | EXPORT_SYMBOL(nf_conntrack_l3proto_register); | ||
838 | EXPORT_SYMBOL(nf_conntrack_l3proto_unregister); | ||
839 | EXPORT_SYMBOL(nf_conntrack_protocol_register); | ||
840 | EXPORT_SYMBOL(nf_conntrack_protocol_unregister); | ||
841 | EXPORT_SYMBOL(nf_ct_invert_tuplepr); | ||
842 | EXPORT_SYMBOL(nf_conntrack_alter_reply); | ||
843 | EXPORT_SYMBOL(nf_conntrack_destroyed); | ||
844 | EXPORT_SYMBOL(need_nf_conntrack); | ||
845 | EXPORT_SYMBOL(nf_conntrack_helper_register); | ||
846 | EXPORT_SYMBOL(nf_conntrack_helper_unregister); | ||
847 | EXPORT_SYMBOL(nf_ct_iterate_cleanup); | ||
848 | EXPORT_SYMBOL(__nf_ct_refresh_acct); | ||
849 | EXPORT_SYMBOL(nf_ct_protos); | ||
850 | EXPORT_SYMBOL(nf_ct_find_proto); | ||
851 | EXPORT_SYMBOL(nf_ct_l3protos); | ||
852 | EXPORT_SYMBOL(nf_conntrack_expect_alloc); | ||
853 | EXPORT_SYMBOL(nf_conntrack_expect_put); | ||
854 | EXPORT_SYMBOL(nf_conntrack_expect_related); | ||
855 | EXPORT_SYMBOL(nf_conntrack_unexpect_related); | ||
856 | EXPORT_SYMBOL(nf_conntrack_tuple_taken); | ||
857 | EXPORT_SYMBOL(nf_conntrack_htable_size); | ||
858 | EXPORT_SYMBOL(nf_conntrack_lock); | ||
859 | EXPORT_SYMBOL(nf_conntrack_hash); | ||
860 | EXPORT_SYMBOL(nf_conntrack_untracked); | ||
861 | EXPORT_SYMBOL_GPL(nf_conntrack_find_get); | ||
862 | #ifdef CONFIG_IP_NF_NAT_NEEDED | ||
863 | EXPORT_SYMBOL(nf_conntrack_tcp_update); | ||
864 | #endif | ||
865 | EXPORT_SYMBOL(__nf_conntrack_confirm); | ||
866 | EXPORT_SYMBOL(nf_ct_get_tuple); | ||
867 | EXPORT_SYMBOL(nf_ct_invert_tuple); | ||
868 | EXPORT_SYMBOL(nf_conntrack_in); | ||
869 | EXPORT_SYMBOL(__nf_conntrack_attach); | ||
diff --git a/net/netlink/Makefile b/net/netlink/Makefile index 39d9c2dcd03c..e3589c2de49e 100644 --- a/net/netlink/Makefile +++ b/net/netlink/Makefile | |||
@@ -2,4 +2,4 @@ | |||
2 | # Makefile for the netlink driver. | 2 | # Makefile for the netlink driver. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y := af_netlink.o | 5 | obj-y := af_netlink.o attr.o genetlink.o |
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 5ca283537bc6..8c38ee6d255e 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -58,6 +58,7 @@ | |||
58 | 58 | ||
59 | #include <net/sock.h> | 59 | #include <net/sock.h> |
60 | #include <net/scm.h> | 60 | #include <net/scm.h> |
61 | #include <net/netlink.h> | ||
61 | 62 | ||
62 | #define Nprintk(a...) | 63 | #define Nprintk(a...) |
63 | #define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8) | 64 | #define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8) |
@@ -427,7 +428,8 @@ static int netlink_release(struct socket *sock) | |||
427 | 428 | ||
428 | spin_lock(&nlk->cb_lock); | 429 | spin_lock(&nlk->cb_lock); |
429 | if (nlk->cb) { | 430 | if (nlk->cb) { |
430 | nlk->cb->done(nlk->cb); | 431 | if (nlk->cb->done) |
432 | nlk->cb->done(nlk->cb); | ||
431 | netlink_destroy_callback(nlk->cb); | 433 | netlink_destroy_callback(nlk->cb); |
432 | nlk->cb = NULL; | 434 | nlk->cb = NULL; |
433 | } | 435 | } |
@@ -1322,7 +1324,8 @@ static int netlink_dump(struct sock *sk) | |||
1322 | skb_queue_tail(&sk->sk_receive_queue, skb); | 1324 | skb_queue_tail(&sk->sk_receive_queue, skb); |
1323 | sk->sk_data_ready(sk, skb->len); | 1325 | sk->sk_data_ready(sk, skb->len); |
1324 | 1326 | ||
1325 | cb->done(cb); | 1327 | if (cb->done) |
1328 | cb->done(cb); | ||
1326 | nlk->cb = NULL; | 1329 | nlk->cb = NULL; |
1327 | spin_unlock(&nlk->cb_lock); | 1330 | spin_unlock(&nlk->cb_lock); |
1328 | 1331 | ||
@@ -1409,6 +1412,94 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) | |||
1409 | netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); | 1412 | netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); |
1410 | } | 1413 | } |
1411 | 1414 | ||
1415 | static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, | ||
1416 | struct nlmsghdr *, int *)) | ||
1417 | { | ||
1418 | unsigned int total_len; | ||
1419 | struct nlmsghdr *nlh; | ||
1420 | int err; | ||
1421 | |||
1422 | while (skb->len >= nlmsg_total_size(0)) { | ||
1423 | nlh = (struct nlmsghdr *) skb->data; | ||
1424 | |||
1425 | if (skb->len < nlh->nlmsg_len) | ||
1426 | return 0; | ||
1427 | |||
1428 | total_len = min(NLMSG_ALIGN(nlh->nlmsg_len), skb->len); | ||
1429 | |||
1430 | if (cb(skb, nlh, &err) < 0) { | ||
1431 | /* Not an error, but we have to interrupt processing | ||
1432 | * here. Note: that in this case we do not pull | ||
1433 | * message from skb, it will be processed later. | ||
1434 | */ | ||
1435 | if (err == 0) | ||
1436 | return -1; | ||
1437 | netlink_ack(skb, nlh, err); | ||
1438 | } else if (nlh->nlmsg_flags & NLM_F_ACK) | ||
1439 | netlink_ack(skb, nlh, 0); | ||
1440 | |||
1441 | skb_pull(skb, total_len); | ||
1442 | } | ||
1443 | |||
1444 | return 0; | ||
1445 | } | ||
1446 | |||
1447 | /** | ||
1448 | * nelink_run_queue - Process netlink receive queue. | ||
1449 | * @sk: Netlink socket containing the queue | ||
1450 | * @qlen: Place to store queue length upon entry | ||
1451 | * @cb: Callback function invoked for each netlink message found | ||
1452 | * | ||
1453 | * Processes as much as there was in the queue upon entry and invokes | ||
1454 | * a callback function for each netlink message found. The callback | ||
1455 | * function may refuse a message by returning a negative error code | ||
1456 | * but setting the error pointer to 0 in which case this function | ||
1457 | * returns with a qlen != 0. | ||
1458 | * | ||
1459 | * qlen must be initialized to 0 before the initial entry, afterwards | ||
1460 | * the function may be called repeatedly until qlen reaches 0. | ||
1461 | */ | ||
1462 | void netlink_run_queue(struct sock *sk, unsigned int *qlen, | ||
1463 | int (*cb)(struct sk_buff *, struct nlmsghdr *, int *)) | ||
1464 | { | ||
1465 | struct sk_buff *skb; | ||
1466 | |||
1467 | if (!*qlen || *qlen > skb_queue_len(&sk->sk_receive_queue)) | ||
1468 | *qlen = skb_queue_len(&sk->sk_receive_queue); | ||
1469 | |||
1470 | for (; *qlen; (*qlen)--) { | ||
1471 | skb = skb_dequeue(&sk->sk_receive_queue); | ||
1472 | if (netlink_rcv_skb(skb, cb)) { | ||
1473 | if (skb->len) | ||
1474 | skb_queue_head(&sk->sk_receive_queue, skb); | ||
1475 | else { | ||
1476 | kfree_skb(skb); | ||
1477 | (*qlen)--; | ||
1478 | } | ||
1479 | break; | ||
1480 | } | ||
1481 | |||
1482 | kfree_skb(skb); | ||
1483 | } | ||
1484 | } | ||
1485 | |||
1486 | /** | ||
1487 | * netlink_queue_skip - Skip netlink message while processing queue. | ||
1488 | * @nlh: Netlink message to be skipped | ||
1489 | * @skb: Socket buffer containing the netlink messages. | ||
1490 | * | ||
1491 | * Pulls the given netlink message off the socket buffer so the next | ||
1492 | * call to netlink_queue_run() will not reconsider the message. | ||
1493 | */ | ||
1494 | void netlink_queue_skip(struct nlmsghdr *nlh, struct sk_buff *skb) | ||
1495 | { | ||
1496 | int msglen = NLMSG_ALIGN(nlh->nlmsg_len); | ||
1497 | |||
1498 | if (msglen > skb->len) | ||
1499 | msglen = skb->len; | ||
1500 | |||
1501 | skb_pull(skb, msglen); | ||
1502 | } | ||
1412 | 1503 | ||
1413 | #ifdef CONFIG_PROC_FS | 1504 | #ifdef CONFIG_PROC_FS |
1414 | struct nl_seq_iter { | 1505 | struct nl_seq_iter { |
@@ -1657,6 +1748,8 @@ out: | |||
1657 | core_initcall(netlink_proto_init); | 1748 | core_initcall(netlink_proto_init); |
1658 | 1749 | ||
1659 | EXPORT_SYMBOL(netlink_ack); | 1750 | EXPORT_SYMBOL(netlink_ack); |
1751 | EXPORT_SYMBOL(netlink_run_queue); | ||
1752 | EXPORT_SYMBOL(netlink_queue_skip); | ||
1660 | EXPORT_SYMBOL(netlink_broadcast); | 1753 | EXPORT_SYMBOL(netlink_broadcast); |
1661 | EXPORT_SYMBOL(netlink_dump_start); | 1754 | EXPORT_SYMBOL(netlink_dump_start); |
1662 | EXPORT_SYMBOL(netlink_kernel_create); | 1755 | EXPORT_SYMBOL(netlink_kernel_create); |
diff --git a/net/netlink/attr.c b/net/netlink/attr.c new file mode 100644 index 000000000000..fffef4ab276f --- /dev/null +++ b/net/netlink/attr.c | |||
@@ -0,0 +1,328 @@ | |||
1 | /* | ||
2 | * NETLINK Netlink attributes | ||
3 | * | ||
4 | * Authors: Thomas Graf <tgraf@suug.ch> | ||
5 | * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> | ||
6 | */ | ||
7 | |||
8 | #include <linux/config.h> | ||
9 | #include <linux/module.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/errno.h> | ||
12 | #include <linux/jiffies.h> | ||
13 | #include <linux/netdevice.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <linux/string.h> | ||
16 | #include <linux/types.h> | ||
17 | #include <net/netlink.h> | ||
18 | |||
19 | static u16 nla_attr_minlen[NLA_TYPE_MAX+1] __read_mostly = { | ||
20 | [NLA_U8] = sizeof(u8), | ||
21 | [NLA_U16] = sizeof(u16), | ||
22 | [NLA_U32] = sizeof(u32), | ||
23 | [NLA_U64] = sizeof(u64), | ||
24 | [NLA_STRING] = 1, | ||
25 | [NLA_NESTED] = NLA_HDRLEN, | ||
26 | }; | ||
27 | |||
28 | static int validate_nla(struct nlattr *nla, int maxtype, | ||
29 | struct nla_policy *policy) | ||
30 | { | ||
31 | struct nla_policy *pt; | ||
32 | int minlen = 0; | ||
33 | |||
34 | if (nla->nla_type <= 0 || nla->nla_type > maxtype) | ||
35 | return 0; | ||
36 | |||
37 | pt = &policy[nla->nla_type]; | ||
38 | |||
39 | BUG_ON(pt->type > NLA_TYPE_MAX); | ||
40 | |||
41 | if (pt->minlen) | ||
42 | minlen = pt->minlen; | ||
43 | else if (pt->type != NLA_UNSPEC) | ||
44 | minlen = nla_attr_minlen[pt->type]; | ||
45 | |||
46 | if (pt->type == NLA_FLAG && nla_len(nla) > 0) | ||
47 | return -ERANGE; | ||
48 | |||
49 | if (nla_len(nla) < minlen) | ||
50 | return -ERANGE; | ||
51 | |||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | /** | ||
56 | * nla_validate - Validate a stream of attributes | ||
57 | * @head: head of attribute stream | ||
58 | * @len: length of attribute stream | ||
59 | * @maxtype: maximum attribute type to be expected | ||
60 | * @policy: validation policy | ||
61 | * | ||
62 | * Validates all attributes in the specified attribute stream against the | ||
63 | * specified policy. Attributes with a type exceeding maxtype will be | ||
64 | * ignored. See documenation of struct nla_policy for more details. | ||
65 | * | ||
66 | * Returns 0 on success or a negative error code. | ||
67 | */ | ||
68 | int nla_validate(struct nlattr *head, int len, int maxtype, | ||
69 | struct nla_policy *policy) | ||
70 | { | ||
71 | struct nlattr *nla; | ||
72 | int rem, err; | ||
73 | |||
74 | nla_for_each_attr(nla, head, len, rem) { | ||
75 | err = validate_nla(nla, maxtype, policy); | ||
76 | if (err < 0) | ||
77 | goto errout; | ||
78 | } | ||
79 | |||
80 | err = 0; | ||
81 | errout: | ||
82 | return err; | ||
83 | } | ||
84 | |||
85 | /** | ||
86 | * nla_parse - Parse a stream of attributes into a tb buffer | ||
87 | * @tb: destination array with maxtype+1 elements | ||
88 | * @maxtype: maximum attribute type to be expected | ||
89 | * @head: head of attribute stream | ||
90 | * @len: length of attribute stream | ||
91 | * | ||
92 | * Parses a stream of attributes and stores a pointer to each attribute in | ||
93 | * the tb array accessable via the attribute type. Attributes with a type | ||
94 | * exceeding maxtype will be silently ignored for backwards compatibility | ||
95 | * reasons. policy may be set to NULL if no validation is required. | ||
96 | * | ||
97 | * Returns 0 on success or a negative error code. | ||
98 | */ | ||
99 | int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len, | ||
100 | struct nla_policy *policy) | ||
101 | { | ||
102 | struct nlattr *nla; | ||
103 | int rem, err; | ||
104 | |||
105 | memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1)); | ||
106 | |||
107 | nla_for_each_attr(nla, head, len, rem) { | ||
108 | u16 type = nla->nla_type; | ||
109 | |||
110 | if (type > 0 && type <= maxtype) { | ||
111 | if (policy) { | ||
112 | err = validate_nla(nla, maxtype, policy); | ||
113 | if (err < 0) | ||
114 | goto errout; | ||
115 | } | ||
116 | |||
117 | tb[type] = nla; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | if (unlikely(rem > 0)) | ||
122 | printk(KERN_WARNING "netlink: %d bytes leftover after parsing " | ||
123 | "attributes.\n", rem); | ||
124 | |||
125 | err = 0; | ||
126 | errout: | ||
127 | return err; | ||
128 | } | ||
129 | |||
130 | /** | ||
131 | * nla_find - Find a specific attribute in a stream of attributes | ||
132 | * @head: head of attribute stream | ||
133 | * @len: length of attribute stream | ||
134 | * @attrtype: type of attribute to look for | ||
135 | * | ||
136 | * Returns the first attribute in the stream matching the specified type. | ||
137 | */ | ||
138 | struct nlattr *nla_find(struct nlattr *head, int len, int attrtype) | ||
139 | { | ||
140 | struct nlattr *nla; | ||
141 | int rem; | ||
142 | |||
143 | nla_for_each_attr(nla, head, len, rem) | ||
144 | if (nla->nla_type == attrtype) | ||
145 | return nla; | ||
146 | |||
147 | return NULL; | ||
148 | } | ||
149 | |||
150 | /** | ||
151 | * nla_strlcpy - Copy string attribute payload into a sized buffer | ||
152 | * @dst: where to copy the string to | ||
153 | * @src: attribute to copy the string from | ||
154 | * @dstsize: size of destination buffer | ||
155 | * | ||
156 | * Copies at most dstsize - 1 bytes into the destination buffer. | ||
157 | * The result is always a valid NUL-terminated string. Unlike | ||
158 | * strlcpy the destination buffer is always padded out. | ||
159 | * | ||
160 | * Returns the length of the source buffer. | ||
161 | */ | ||
162 | size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize) | ||
163 | { | ||
164 | size_t srclen = nla_len(nla); | ||
165 | char *src = nla_data(nla); | ||
166 | |||
167 | if (srclen > 0 && src[srclen - 1] == '\0') | ||
168 | srclen--; | ||
169 | |||
170 | if (dstsize > 0) { | ||
171 | size_t len = (srclen >= dstsize) ? dstsize - 1 : srclen; | ||
172 | |||
173 | memset(dst, 0, dstsize); | ||
174 | memcpy(dst, src, len); | ||
175 | } | ||
176 | |||
177 | return srclen; | ||
178 | } | ||
179 | |||
180 | /** | ||
181 | * nla_memcpy - Copy a netlink attribute into another memory area | ||
182 | * @dest: where to copy to memcpy | ||
183 | * @src: netlink attribute to copy from | ||
184 | * @count: size of the destination area | ||
185 | * | ||
186 | * Note: The number of bytes copied is limited by the length of | ||
187 | * attribute's payload. memcpy | ||
188 | * | ||
189 | * Returns the number of bytes copied. | ||
190 | */ | ||
191 | int nla_memcpy(void *dest, struct nlattr *src, int count) | ||
192 | { | ||
193 | int minlen = min_t(int, count, nla_len(src)); | ||
194 | |||
195 | memcpy(dest, nla_data(src), minlen); | ||
196 | |||
197 | return minlen; | ||
198 | } | ||
199 | |||
200 | /** | ||
201 | * nla_memcmp - Compare an attribute with sized memory area | ||
202 | * @nla: netlink attribute | ||
203 | * @data: memory area | ||
204 | * @size: size of memory area | ||
205 | */ | ||
206 | int nla_memcmp(const struct nlattr *nla, const void *data, | ||
207 | size_t size) | ||
208 | { | ||
209 | int d = nla_len(nla) - size; | ||
210 | |||
211 | if (d == 0) | ||
212 | d = memcmp(nla_data(nla), data, size); | ||
213 | |||
214 | return d; | ||
215 | } | ||
216 | |||
217 | /** | ||
218 | * nla_strcmp - Compare a string attribute against a string | ||
219 | * @nla: netlink string attribute | ||
220 | * @str: another string | ||
221 | */ | ||
222 | int nla_strcmp(const struct nlattr *nla, const char *str) | ||
223 | { | ||
224 | int len = strlen(str) + 1; | ||
225 | int d = nla_len(nla) - len; | ||
226 | |||
227 | if (d == 0) | ||
228 | d = memcmp(nla_data(nla), str, len); | ||
229 | |||
230 | return d; | ||
231 | } | ||
232 | |||
233 | /** | ||
234 | * __nla_reserve - reserve room for attribute on the skb | ||
235 | * @skb: socket buffer to reserve room on | ||
236 | * @attrtype: attribute type | ||
237 | * @attrlen: length of attribute payload | ||
238 | * | ||
239 | * Adds a netlink attribute header to a socket buffer and reserves | ||
240 | * room for the payload but does not copy it. | ||
241 | * | ||
242 | * The caller is responsible to ensure that the skb provides enough | ||
243 | * tailroom for the attribute header and payload. | ||
244 | */ | ||
245 | struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen) | ||
246 | { | ||
247 | struct nlattr *nla; | ||
248 | |||
249 | nla = (struct nlattr *) skb_put(skb, nla_total_size(attrlen)); | ||
250 | nla->nla_type = attrtype; | ||
251 | nla->nla_len = nla_attr_size(attrlen); | ||
252 | |||
253 | memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen)); | ||
254 | |||
255 | return nla; | ||
256 | } | ||
257 | |||
258 | /** | ||
259 | * nla_reserve - reserve room for attribute on the skb | ||
260 | * @skb: socket buffer to reserve room on | ||
261 | * @attrtype: attribute type | ||
262 | * @attrlen: length of attribute payload | ||
263 | * | ||
264 | * Adds a netlink attribute header to a socket buffer and reserves | ||
265 | * room for the payload but does not copy it. | ||
266 | * | ||
267 | * Returns NULL if the tailroom of the skb is insufficient to store | ||
268 | * the attribute header and payload. | ||
269 | */ | ||
270 | struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen) | ||
271 | { | ||
272 | if (unlikely(skb_tailroom(skb) < nla_total_size(attrlen))) | ||
273 | return NULL; | ||
274 | |||
275 | return __nla_reserve(skb, attrtype, attrlen); | ||
276 | } | ||
277 | |||
278 | /** | ||
279 | * __nla_put - Add a netlink attribute to a socket buffer | ||
280 | * @skb: socket buffer to add attribute to | ||
281 | * @attrtype: attribute type | ||
282 | * @attrlen: length of attribute payload | ||
283 | * @data: head of attribute payload | ||
284 | * | ||
285 | * The caller is responsible to ensure that the skb provides enough | ||
286 | * tailroom for the attribute header and payload. | ||
287 | */ | ||
288 | void __nla_put(struct sk_buff *skb, int attrtype, int attrlen, | ||
289 | const void *data) | ||
290 | { | ||
291 | struct nlattr *nla; | ||
292 | |||
293 | nla = __nla_reserve(skb, attrtype, attrlen); | ||
294 | memcpy(nla_data(nla), data, attrlen); | ||
295 | } | ||
296 | |||
297 | |||
298 | /** | ||
299 | * nla_put - Add a netlink attribute to a socket buffer | ||
300 | * @skb: socket buffer to add attribute to | ||
301 | * @attrtype: attribute type | ||
302 | * @attrlen: length of attribute payload | ||
303 | * @data: head of attribute payload | ||
304 | * | ||
305 | * Returns -1 if the tailroom of the skb is insufficient to store | ||
306 | * the attribute header and payload. | ||
307 | */ | ||
308 | int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data) | ||
309 | { | ||
310 | if (unlikely(skb_tailroom(skb) < nla_total_size(attrlen))) | ||
311 | return -1; | ||
312 | |||
313 | __nla_put(skb, attrtype, attrlen, data); | ||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | |||
318 | EXPORT_SYMBOL(nla_validate); | ||
319 | EXPORT_SYMBOL(nla_parse); | ||
320 | EXPORT_SYMBOL(nla_find); | ||
321 | EXPORT_SYMBOL(nla_strlcpy); | ||
322 | EXPORT_SYMBOL(__nla_reserve); | ||
323 | EXPORT_SYMBOL(nla_reserve); | ||
324 | EXPORT_SYMBOL(__nla_put); | ||
325 | EXPORT_SYMBOL(nla_put); | ||
326 | EXPORT_SYMBOL(nla_memcpy); | ||
327 | EXPORT_SYMBOL(nla_memcmp); | ||
328 | EXPORT_SYMBOL(nla_strcmp); | ||
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c new file mode 100644 index 000000000000..287cfcc56951 --- /dev/null +++ b/net/netlink/genetlink.c | |||
@@ -0,0 +1,579 @@ | |||
1 | /* | ||
2 | * NETLINK Generic Netlink Family | ||
3 | * | ||
4 | * Authors: Jamal Hadi Salim | ||
5 | * Thomas Graf <tgraf@suug.ch> | ||
6 | */ | ||
7 | |||
8 | #include <linux/config.h> | ||
9 | #include <linux/module.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/errno.h> | ||
12 | #include <linux/types.h> | ||
13 | #include <linux/socket.h> | ||
14 | #include <linux/string.h> | ||
15 | #include <linux/skbuff.h> | ||
16 | #include <net/sock.h> | ||
17 | #include <net/genetlink.h> | ||
18 | |||
19 | struct sock *genl_sock = NULL; | ||
20 | |||
21 | static DECLARE_MUTEX(genl_sem); /* serialization of message processing */ | ||
22 | |||
23 | static void genl_lock(void) | ||
24 | { | ||
25 | down(&genl_sem); | ||
26 | } | ||
27 | |||
28 | static int genl_trylock(void) | ||
29 | { | ||
30 | return down_trylock(&genl_sem); | ||
31 | } | ||
32 | |||
33 | static void genl_unlock(void) | ||
34 | { | ||
35 | up(&genl_sem); | ||
36 | |||
37 | if (genl_sock && genl_sock->sk_receive_queue.qlen) | ||
38 | genl_sock->sk_data_ready(genl_sock, 0); | ||
39 | } | ||
40 | |||
41 | #define GENL_FAM_TAB_SIZE 16 | ||
42 | #define GENL_FAM_TAB_MASK (GENL_FAM_TAB_SIZE - 1) | ||
43 | |||
44 | static struct list_head family_ht[GENL_FAM_TAB_SIZE]; | ||
45 | |||
46 | static int genl_ctrl_event(int event, void *data); | ||
47 | |||
48 | static inline unsigned int genl_family_hash(unsigned int id) | ||
49 | { | ||
50 | return id & GENL_FAM_TAB_MASK; | ||
51 | } | ||
52 | |||
53 | static inline struct list_head *genl_family_chain(unsigned int id) | ||
54 | { | ||
55 | return &family_ht[genl_family_hash(id)]; | ||
56 | } | ||
57 | |||
58 | static struct genl_family *genl_family_find_byid(unsigned int id) | ||
59 | { | ||
60 | struct genl_family *f; | ||
61 | |||
62 | list_for_each_entry(f, genl_family_chain(id), family_list) | ||
63 | if (f->id == id) | ||
64 | return f; | ||
65 | |||
66 | return NULL; | ||
67 | } | ||
68 | |||
69 | static struct genl_family *genl_family_find_byname(char *name) | ||
70 | { | ||
71 | struct genl_family *f; | ||
72 | int i; | ||
73 | |||
74 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) | ||
75 | list_for_each_entry(f, genl_family_chain(i), family_list) | ||
76 | if (strcmp(f->name, name) == 0) | ||
77 | return f; | ||
78 | |||
79 | return NULL; | ||
80 | } | ||
81 | |||
82 | static struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family) | ||
83 | { | ||
84 | struct genl_ops *ops; | ||
85 | |||
86 | list_for_each_entry(ops, &family->ops_list, ops_list) | ||
87 | if (ops->cmd == cmd) | ||
88 | return ops; | ||
89 | |||
90 | return NULL; | ||
91 | } | ||
92 | |||
93 | /* Of course we are going to have problems once we hit | ||
94 | * 2^16 alive types, but that can only happen by year 2K | ||
95 | */ | ||
96 | static inline u16 genl_generate_id(void) | ||
97 | { | ||
98 | static u16 id_gen_idx; | ||
99 | int overflowed = 0; | ||
100 | |||
101 | do { | ||
102 | if (id_gen_idx == 0) | ||
103 | id_gen_idx = GENL_MIN_ID; | ||
104 | |||
105 | if (++id_gen_idx > GENL_MAX_ID) { | ||
106 | if (!overflowed) { | ||
107 | overflowed = 1; | ||
108 | id_gen_idx = 0; | ||
109 | continue; | ||
110 | } else | ||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | } while (genl_family_find_byid(id_gen_idx)); | ||
115 | |||
116 | return id_gen_idx; | ||
117 | } | ||
118 | |||
119 | /** | ||
120 | * genl_register_ops - register generic netlink operations | ||
121 | * @family: generic netlink family | ||
122 | * @ops: operations to be registered | ||
123 | * | ||
124 | * Registers the specified operations and assigns them to the specified | ||
125 | * family. Either a doit or dumpit callback must be specified or the | ||
126 | * operation will fail. Only one operation structure per command | ||
127 | * identifier may be registered. | ||
128 | * | ||
129 | * See include/net/genetlink.h for more documenation on the operations | ||
130 | * structure. | ||
131 | * | ||
132 | * Returns 0 on success or a negative error code. | ||
133 | */ | ||
134 | int genl_register_ops(struct genl_family *family, struct genl_ops *ops) | ||
135 | { | ||
136 | int err = -EINVAL; | ||
137 | |||
138 | if (ops->dumpit == NULL && ops->doit == NULL) | ||
139 | goto errout; | ||
140 | |||
141 | if (genl_get_cmd(ops->cmd, family)) { | ||
142 | err = -EEXIST; | ||
143 | goto errout; | ||
144 | } | ||
145 | |||
146 | genl_lock(); | ||
147 | list_add_tail(&ops->ops_list, &family->ops_list); | ||
148 | genl_unlock(); | ||
149 | |||
150 | genl_ctrl_event(CTRL_CMD_NEWOPS, ops); | ||
151 | err = 0; | ||
152 | errout: | ||
153 | return err; | ||
154 | } | ||
155 | |||
156 | /** | ||
157 | * genl_unregister_ops - unregister generic netlink operations | ||
158 | * @family: generic netlink family | ||
159 | * @ops: operations to be unregistered | ||
160 | * | ||
161 | * Unregisters the specified operations and unassigns them from the | ||
162 | * specified family. The operation blocks until the current message | ||
163 | * processing has finished and doesn't start again until the | ||
164 | * unregister process has finished. | ||
165 | * | ||
166 | * Note: It is not necessary to unregister all operations before | ||
167 | * unregistering the family, unregistering the family will cause | ||
168 | * all assigned operations to be unregistered automatically. | ||
169 | * | ||
170 | * Returns 0 on success or a negative error code. | ||
171 | */ | ||
172 | int genl_unregister_ops(struct genl_family *family, struct genl_ops *ops) | ||
173 | { | ||
174 | struct genl_ops *rc; | ||
175 | |||
176 | genl_lock(); | ||
177 | list_for_each_entry(rc, &family->ops_list, ops_list) { | ||
178 | if (rc == ops) { | ||
179 | list_del(&ops->ops_list); | ||
180 | genl_unlock(); | ||
181 | genl_ctrl_event(CTRL_CMD_DELOPS, ops); | ||
182 | return 0; | ||
183 | } | ||
184 | } | ||
185 | genl_unlock(); | ||
186 | |||
187 | return -ENOENT; | ||
188 | } | ||
189 | |||
190 | /** | ||
191 | * genl_register_family - register a generic netlink family | ||
192 | * @family: generic netlink family | ||
193 | * | ||
194 | * Registers the specified family after validating it first. Only one | ||
195 | * family may be registered with the same family name or identifier. | ||
196 | * The family id may equal GENL_ID_GENERATE causing an unique id to | ||
197 | * be automatically generated and assigned. | ||
198 | * | ||
199 | * Return 0 on success or a negative error code. | ||
200 | */ | ||
201 | int genl_register_family(struct genl_family *family) | ||
202 | { | ||
203 | int err = -EINVAL; | ||
204 | |||
205 | if (family->id && family->id < GENL_MIN_ID) | ||
206 | goto errout; | ||
207 | |||
208 | if (family->id > GENL_MAX_ID) | ||
209 | goto errout; | ||
210 | |||
211 | INIT_LIST_HEAD(&family->ops_list); | ||
212 | |||
213 | genl_lock(); | ||
214 | |||
215 | if (genl_family_find_byname(family->name)) { | ||
216 | err = -EEXIST; | ||
217 | goto errout_locked; | ||
218 | } | ||
219 | |||
220 | if (genl_family_find_byid(family->id)) { | ||
221 | err = -EEXIST; | ||
222 | goto errout_locked; | ||
223 | } | ||
224 | |||
225 | if (!try_module_get(family->owner)) { | ||
226 | err = -EBUSY; | ||
227 | goto errout_locked; | ||
228 | } | ||
229 | |||
230 | if (family->id == GENL_ID_GENERATE) { | ||
231 | u16 newid = genl_generate_id(); | ||
232 | |||
233 | if (!newid) { | ||
234 | err = -ENOMEM; | ||
235 | goto errout_locked; | ||
236 | } | ||
237 | |||
238 | family->id = newid; | ||
239 | } | ||
240 | |||
241 | if (family->maxattr) { | ||
242 | family->attrbuf = kmalloc((family->maxattr+1) * | ||
243 | sizeof(struct nlattr *), GFP_KERNEL); | ||
244 | if (family->attrbuf == NULL) { | ||
245 | err = -ENOMEM; | ||
246 | goto errout; | ||
247 | } | ||
248 | } else | ||
249 | family->attrbuf = NULL; | ||
250 | |||
251 | list_add_tail(&family->family_list, genl_family_chain(family->id)); | ||
252 | genl_unlock(); | ||
253 | |||
254 | genl_ctrl_event(CTRL_CMD_NEWFAMILY, family); | ||
255 | |||
256 | return 0; | ||
257 | |||
258 | errout_locked: | ||
259 | genl_unlock(); | ||
260 | errout: | ||
261 | return err; | ||
262 | } | ||
263 | |||
264 | /** | ||
265 | * genl_unregister_family - unregister generic netlink family | ||
266 | * @family: generic netlink family | ||
267 | * | ||
268 | * Unregisters the specified family. | ||
269 | * | ||
270 | * Returns 0 on success or a negative error code. | ||
271 | */ | ||
272 | int genl_unregister_family(struct genl_family *family) | ||
273 | { | ||
274 | struct genl_family *rc; | ||
275 | |||
276 | genl_lock(); | ||
277 | |||
278 | list_for_each_entry(rc, genl_family_chain(family->id), family_list) { | ||
279 | if (family->id != rc->id || strcmp(rc->name, family->name)) | ||
280 | continue; | ||
281 | |||
282 | list_del(&rc->family_list); | ||
283 | INIT_LIST_HEAD(&family->ops_list); | ||
284 | genl_unlock(); | ||
285 | |||
286 | module_put(family->owner); | ||
287 | kfree(family->attrbuf); | ||
288 | genl_ctrl_event(CTRL_CMD_DELFAMILY, family); | ||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | genl_unlock(); | ||
293 | |||
294 | return -ENOENT; | ||
295 | } | ||
296 | |||
297 | static inline int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, | ||
298 | int *errp) | ||
299 | { | ||
300 | struct genl_ops *ops; | ||
301 | struct genl_family *family; | ||
302 | struct genl_info info; | ||
303 | struct genlmsghdr *hdr = nlmsg_data(nlh); | ||
304 | int hdrlen, err = -EINVAL; | ||
305 | |||
306 | if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) | ||
307 | goto ignore; | ||
308 | |||
309 | if (nlh->nlmsg_type < NLMSG_MIN_TYPE) | ||
310 | goto ignore; | ||
311 | |||
312 | family = genl_family_find_byid(nlh->nlmsg_type); | ||
313 | if (family == NULL) { | ||
314 | err = -ENOENT; | ||
315 | goto errout; | ||
316 | } | ||
317 | |||
318 | hdrlen = GENL_HDRLEN + family->hdrsize; | ||
319 | if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) | ||
320 | goto errout; | ||
321 | |||
322 | ops = genl_get_cmd(hdr->cmd, family); | ||
323 | if (ops == NULL) { | ||
324 | err = -EOPNOTSUPP; | ||
325 | goto errout; | ||
326 | } | ||
327 | |||
328 | if ((ops->flags & GENL_ADMIN_PERM) && security_netlink_recv(skb)) { | ||
329 | err = -EPERM; | ||
330 | goto errout; | ||
331 | } | ||
332 | |||
333 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | ||
334 | if (ops->dumpit == NULL) { | ||
335 | err = -EOPNOTSUPP; | ||
336 | goto errout; | ||
337 | } | ||
338 | |||
339 | *errp = err = netlink_dump_start(genl_sock, skb, nlh, | ||
340 | ops->dumpit, NULL); | ||
341 | if (err == 0) | ||
342 | skb_pull(skb, min(NLMSG_ALIGN(nlh->nlmsg_len), | ||
343 | skb->len)); | ||
344 | return -1; | ||
345 | } | ||
346 | |||
347 | if (ops->doit == NULL) { | ||
348 | err = -EOPNOTSUPP; | ||
349 | goto errout; | ||
350 | } | ||
351 | |||
352 | if (family->attrbuf) { | ||
353 | err = nlmsg_parse(nlh, hdrlen, family->attrbuf, family->maxattr, | ||
354 | ops->policy); | ||
355 | if (err < 0) | ||
356 | goto errout; | ||
357 | } | ||
358 | |||
359 | info.snd_seq = nlh->nlmsg_seq; | ||
360 | info.snd_pid = NETLINK_CB(skb).pid; | ||
361 | info.nlhdr = nlh; | ||
362 | info.genlhdr = nlmsg_data(nlh); | ||
363 | info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN; | ||
364 | info.attrs = family->attrbuf; | ||
365 | |||
366 | *errp = err = ops->doit(skb, &info); | ||
367 | return err; | ||
368 | |||
369 | ignore: | ||
370 | return 0; | ||
371 | |||
372 | errout: | ||
373 | *errp = err; | ||
374 | return -1; | ||
375 | } | ||
376 | |||
377 | static void genl_rcv(struct sock *sk, int len) | ||
378 | { | ||
379 | unsigned int qlen = 0; | ||
380 | |||
381 | do { | ||
382 | if (genl_trylock()) | ||
383 | return; | ||
384 | netlink_run_queue(sk, &qlen, &genl_rcv_msg); | ||
385 | genl_unlock(); | ||
386 | } while (qlen && genl_sock && genl_sock->sk_receive_queue.qlen); | ||
387 | } | ||
388 | |||
389 | /************************************************************************** | ||
390 | * Controller | ||
391 | **************************************************************************/ | ||
392 | |||
393 | static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq, | ||
394 | u32 flags, struct sk_buff *skb, u8 cmd) | ||
395 | { | ||
396 | void *hdr; | ||
397 | |||
398 | hdr = genlmsg_put(skb, pid, seq, GENL_ID_CTRL, 0, flags, cmd, | ||
399 | family->version); | ||
400 | if (hdr == NULL) | ||
401 | return -1; | ||
402 | |||
403 | NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, family->name); | ||
404 | NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, family->id); | ||
405 | |||
406 | return genlmsg_end(skb, hdr); | ||
407 | |||
408 | nla_put_failure: | ||
409 | return genlmsg_cancel(skb, hdr); | ||
410 | } | ||
411 | |||
412 | static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) | ||
413 | { | ||
414 | |||
415 | int i, n = 0; | ||
416 | struct genl_family *rt; | ||
417 | int chains_to_skip = cb->args[0]; | ||
418 | int fams_to_skip = cb->args[1]; | ||
419 | |||
420 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { | ||
421 | if (i < chains_to_skip) | ||
422 | continue; | ||
423 | n = 0; | ||
424 | list_for_each_entry(rt, genl_family_chain(i), family_list) { | ||
425 | if (++n < fams_to_skip) | ||
426 | continue; | ||
427 | if (ctrl_fill_info(rt, NETLINK_CB(cb->skb).pid, | ||
428 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
429 | skb, CTRL_CMD_NEWFAMILY) < 0) | ||
430 | goto errout; | ||
431 | } | ||
432 | |||
433 | fams_to_skip = 0; | ||
434 | } | ||
435 | |||
436 | errout: | ||
437 | cb->args[0] = i; | ||
438 | cb->args[1] = n; | ||
439 | |||
440 | return skb->len; | ||
441 | } | ||
442 | |||
443 | static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid, | ||
444 | int seq, int cmd) | ||
445 | { | ||
446 | struct sk_buff *skb; | ||
447 | int err; | ||
448 | |||
449 | skb = nlmsg_new(NLMSG_GOODSIZE); | ||
450 | if (skb == NULL) | ||
451 | return ERR_PTR(-ENOBUFS); | ||
452 | |||
453 | err = ctrl_fill_info(family, pid, seq, 0, skb, cmd); | ||
454 | if (err < 0) { | ||
455 | nlmsg_free(skb); | ||
456 | return ERR_PTR(err); | ||
457 | } | ||
458 | |||
459 | return skb; | ||
460 | } | ||
461 | |||
462 | static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] __read_mostly = { | ||
463 | [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 }, | ||
464 | [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_STRING }, | ||
465 | }; | ||
466 | |||
467 | static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info) | ||
468 | { | ||
469 | struct sk_buff *msg; | ||
470 | struct genl_family *res = NULL; | ||
471 | int err = -EINVAL; | ||
472 | |||
473 | if (info->attrs[CTRL_ATTR_FAMILY_ID]) { | ||
474 | u16 id = nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]); | ||
475 | res = genl_family_find_byid(id); | ||
476 | } | ||
477 | |||
478 | if (info->attrs[CTRL_ATTR_FAMILY_NAME]) { | ||
479 | char name[GENL_NAMSIZ]; | ||
480 | |||
481 | if (nla_strlcpy(name, info->attrs[CTRL_ATTR_FAMILY_NAME], | ||
482 | GENL_NAMSIZ) >= GENL_NAMSIZ) | ||
483 | goto errout; | ||
484 | |||
485 | res = genl_family_find_byname(name); | ||
486 | } | ||
487 | |||
488 | if (res == NULL) { | ||
489 | err = -ENOENT; | ||
490 | goto errout; | ||
491 | } | ||
492 | |||
493 | msg = ctrl_build_msg(res, info->snd_pid, info->snd_seq, | ||
494 | CTRL_CMD_NEWFAMILY); | ||
495 | if (IS_ERR(msg)) { | ||
496 | err = PTR_ERR(msg); | ||
497 | goto errout; | ||
498 | } | ||
499 | |||
500 | err = genlmsg_unicast(msg, info->snd_pid); | ||
501 | errout: | ||
502 | return err; | ||
503 | } | ||
504 | |||
505 | static int genl_ctrl_event(int event, void *data) | ||
506 | { | ||
507 | struct sk_buff *msg; | ||
508 | |||
509 | if (genl_sock == NULL) | ||
510 | return 0; | ||
511 | |||
512 | switch (event) { | ||
513 | case CTRL_CMD_NEWFAMILY: | ||
514 | case CTRL_CMD_DELFAMILY: | ||
515 | msg = ctrl_build_msg(data, 0, 0, event); | ||
516 | if (IS_ERR(msg)) | ||
517 | return PTR_ERR(msg); | ||
518 | |||
519 | genlmsg_multicast(msg, 0, GENL_ID_CTRL); | ||
520 | break; | ||
521 | } | ||
522 | |||
523 | return 0; | ||
524 | } | ||
525 | |||
526 | static struct genl_ops genl_ctrl_ops = { | ||
527 | .cmd = CTRL_CMD_GETFAMILY, | ||
528 | .doit = ctrl_getfamily, | ||
529 | .dumpit = ctrl_dumpfamily, | ||
530 | .policy = ctrl_policy, | ||
531 | }; | ||
532 | |||
533 | static struct genl_family genl_ctrl = { | ||
534 | .id = GENL_ID_CTRL, | ||
535 | .name = "nlctrl", | ||
536 | .version = 0x1, | ||
537 | .maxattr = CTRL_ATTR_MAX, | ||
538 | .owner = THIS_MODULE, | ||
539 | }; | ||
540 | |||
541 | static int __init genl_init(void) | ||
542 | { | ||
543 | int i, err; | ||
544 | |||
545 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) | ||
546 | INIT_LIST_HEAD(&family_ht[i]); | ||
547 | |||
548 | err = genl_register_family(&genl_ctrl); | ||
549 | if (err < 0) | ||
550 | goto errout; | ||
551 | |||
552 | err = genl_register_ops(&genl_ctrl, &genl_ctrl_ops); | ||
553 | if (err < 0) | ||
554 | goto errout_register; | ||
555 | |||
556 | netlink_set_nonroot(NETLINK_GENERIC, NL_NONROOT_RECV); | ||
557 | genl_sock = netlink_kernel_create(NETLINK_GENERIC, GENL_MAX_ID, | ||
558 | genl_rcv, THIS_MODULE); | ||
559 | if (genl_sock == NULL) { | ||
560 | panic("GENL: Cannot initialize generic netlink\n"); | ||
561 | return -ENOMEM; | ||
562 | } | ||
563 | |||
564 | return 0; | ||
565 | |||
566 | errout_register: | ||
567 | genl_unregister_family(&genl_ctrl); | ||
568 | errout: | ||
569 | panic("GENL: Cannot register controller: %d\n", err); | ||
570 | return err; | ||
571 | } | ||
572 | |||
573 | subsys_initcall(genl_init); | ||
574 | |||
575 | EXPORT_SYMBOL(genl_sock); | ||
576 | EXPORT_SYMBOL(genl_register_ops); | ||
577 | EXPORT_SYMBOL(genl_unregister_ops); | ||
578 | EXPORT_SYMBOL(genl_register_family); | ||
579 | EXPORT_SYMBOL(genl_unregister_family); | ||
diff --git a/net/rxrpc/transport.c b/net/rxrpc/transport.c index 122c086ee2db..dbe6105e83a5 100644 --- a/net/rxrpc/transport.c +++ b/net/rxrpc/transport.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/in.h> | 23 | #include <linux/in.h> |
24 | #include <linux/in6.h> | 24 | #include <linux/in6.h> |
25 | #include <linux/icmp.h> | 25 | #include <linux/icmp.h> |
26 | #include <linux/skbuff.h> | ||
26 | #include <net/sock.h> | 27 | #include <net/sock.h> |
27 | #include <net/ip.h> | 28 | #include <net/ip.h> |
28 | #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) | 29 | #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) |
@@ -475,15 +476,11 @@ void rxrpc_trans_receive_packet(struct rxrpc_transport *trans) | |||
475 | 476 | ||
476 | /* we'll probably need to checksum it (didn't call | 477 | /* we'll probably need to checksum it (didn't call |
477 | * sock_recvmsg) */ | 478 | * sock_recvmsg) */ |
478 | if (pkt->ip_summed != CHECKSUM_UNNECESSARY) { | 479 | if (skb_checksum_complete(pkt)) { |
479 | if ((unsigned short) | 480 | kfree_skb(pkt); |
480 | csum_fold(skb_checksum(pkt, 0, pkt->len, | 481 | rxrpc_krxiod_queue_transport(trans); |
481 | pkt->csum))) { | 482 | _leave(" CSUM failed"); |
482 | kfree_skb(pkt); | 483 | return; |
483 | rxrpc_krxiod_queue_transport(trans); | ||
484 | _leave(" CSUM failed"); | ||
485 | return; | ||
486 | } | ||
487 | } | 484 | } |
488 | 485 | ||
489 | addr = pkt->nh.iph->saddr; | 486 | addr = pkt->nh.iph->saddr; |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 702ede309b06..61c3abeaccae 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -55,6 +55,7 @@ static void call_bind(struct rpc_task *task); | |||
55 | static void call_bind_status(struct rpc_task *task); | 55 | static void call_bind_status(struct rpc_task *task); |
56 | static void call_transmit(struct rpc_task *task); | 56 | static void call_transmit(struct rpc_task *task); |
57 | static void call_status(struct rpc_task *task); | 57 | static void call_status(struct rpc_task *task); |
58 | static void call_transmit_status(struct rpc_task *task); | ||
58 | static void call_refresh(struct rpc_task *task); | 59 | static void call_refresh(struct rpc_task *task); |
59 | static void call_refreshresult(struct rpc_task *task); | 60 | static void call_refreshresult(struct rpc_task *task); |
60 | static void call_timeout(struct rpc_task *task); | 61 | static void call_timeout(struct rpc_task *task); |
@@ -672,6 +673,18 @@ call_allocate(struct rpc_task *task) | |||
672 | rpc_exit(task, -ERESTARTSYS); | 673 | rpc_exit(task, -ERESTARTSYS); |
673 | } | 674 | } |
674 | 675 | ||
676 | static inline int | ||
677 | rpc_task_need_encode(struct rpc_task *task) | ||
678 | { | ||
679 | return task->tk_rqstp->rq_snd_buf.len == 0; | ||
680 | } | ||
681 | |||
682 | static inline void | ||
683 | rpc_task_force_reencode(struct rpc_task *task) | ||
684 | { | ||
685 | task->tk_rqstp->rq_snd_buf.len = 0; | ||
686 | } | ||
687 | |||
675 | /* | 688 | /* |
676 | * 3. Encode arguments of an RPC call | 689 | * 3. Encode arguments of an RPC call |
677 | */ | 690 | */ |
@@ -867,12 +880,14 @@ call_transmit(struct rpc_task *task) | |||
867 | if (task->tk_status != 0) | 880 | if (task->tk_status != 0) |
868 | return; | 881 | return; |
869 | /* Encode here so that rpcsec_gss can use correct sequence number. */ | 882 | /* Encode here so that rpcsec_gss can use correct sequence number. */ |
870 | if (task->tk_rqstp->rq_bytes_sent == 0) { | 883 | if (rpc_task_need_encode(task)) { |
884 | task->tk_rqstp->rq_bytes_sent = 0; | ||
871 | call_encode(task); | 885 | call_encode(task); |
872 | /* Did the encode result in an error condition? */ | 886 | /* Did the encode result in an error condition? */ |
873 | if (task->tk_status != 0) | 887 | if (task->tk_status != 0) |
874 | goto out_nosend; | 888 | goto out_nosend; |
875 | } | 889 | } |
890 | task->tk_action = call_transmit_status; | ||
876 | xprt_transmit(task); | 891 | xprt_transmit(task); |
877 | if (task->tk_status < 0) | 892 | if (task->tk_status < 0) |
878 | return; | 893 | return; |
@@ -884,6 +899,7 @@ call_transmit(struct rpc_task *task) | |||
884 | out_nosend: | 899 | out_nosend: |
885 | /* release socket write lock before attempting to handle error */ | 900 | /* release socket write lock before attempting to handle error */ |
886 | xprt_abort_transmit(task); | 901 | xprt_abort_transmit(task); |
902 | rpc_task_force_reencode(task); | ||
887 | } | 903 | } |
888 | 904 | ||
889 | /* | 905 | /* |
@@ -915,7 +931,6 @@ call_status(struct rpc_task *task) | |||
915 | break; | 931 | break; |
916 | case -ECONNREFUSED: | 932 | case -ECONNREFUSED: |
917 | case -ENOTCONN: | 933 | case -ENOTCONN: |
918 | req->rq_bytes_sent = 0; | ||
919 | if (clnt->cl_autobind) | 934 | if (clnt->cl_autobind) |
920 | clnt->cl_port = 0; | 935 | clnt->cl_port = 0; |
921 | task->tk_action = call_bind; | 936 | task->tk_action = call_bind; |
@@ -937,7 +952,18 @@ call_status(struct rpc_task *task) | |||
937 | } | 952 | } |
938 | 953 | ||
939 | /* | 954 | /* |
940 | * 6a. Handle RPC timeout | 955 | * 6a. Handle transmission errors. |
956 | */ | ||
957 | static void | ||
958 | call_transmit_status(struct rpc_task *task) | ||
959 | { | ||
960 | if (task->tk_status != -EAGAIN) | ||
961 | rpc_task_force_reencode(task); | ||
962 | call_status(task); | ||
963 | } | ||
964 | |||
965 | /* | ||
966 | * 6b. Handle RPC timeout | ||
941 | * We do not release the request slot, so we keep using the | 967 | * We do not release the request slot, so we keep using the |
942 | * same XID for all retransmits. | 968 | * same XID for all retransmits. |
943 | */ | 969 | */ |
diff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c index 8f97e90f36c8..eb330d4f66d6 100644 --- a/net/sunrpc/socklib.c +++ b/net/sunrpc/socklib.c | |||
@@ -6,6 +6,9 @@ | |||
6 | * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> | 6 | * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/compiler.h> | ||
10 | #include <linux/netdevice.h> | ||
11 | #include <linux/skbuff.h> | ||
9 | #include <linux/types.h> | 12 | #include <linux/types.h> |
10 | #include <linux/pagemap.h> | 13 | #include <linux/pagemap.h> |
11 | #include <linux/udp.h> | 14 | #include <linux/udp.h> |
@@ -165,6 +168,8 @@ int csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb) | |||
165 | return -1; | 168 | return -1; |
166 | if ((unsigned short)csum_fold(desc.csum)) | 169 | if ((unsigned short)csum_fold(desc.csum)) |
167 | return -1; | 170 | return -1; |
171 | if (unlikely(skb->ip_summed == CHECKSUM_HW)) | ||
172 | netdev_rx_csum_fault(skb->dev); | ||
168 | return 0; | 173 | return 0; |
169 | no_checksum: | 174 | no_checksum: |
170 | if (xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_bits) < 0) | 175 | if (xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_bits) < 0) |
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index f16e7cdd6150..e50e7cf43737 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
@@ -623,12 +623,9 @@ svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
623 | /* we can use it in-place */ | 623 | /* we can use it in-place */ |
624 | rqstp->rq_arg.head[0].iov_base = skb->data + sizeof(struct udphdr); | 624 | rqstp->rq_arg.head[0].iov_base = skb->data + sizeof(struct udphdr); |
625 | rqstp->rq_arg.head[0].iov_len = len; | 625 | rqstp->rq_arg.head[0].iov_len = len; |
626 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) { | 626 | if (skb_checksum_complete(skb)) { |
627 | if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) { | 627 | skb_free_datagram(svsk->sk_sk, skb); |
628 | skb_free_datagram(svsk->sk_sk, skb); | 628 | return 0; |
629 | return 0; | ||
630 | } | ||
631 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
632 | } | 629 | } |
633 | rqstp->rq_skbuff = skb; | 630 | rqstp->rq_skbuff = skb; |
634 | } | 631 | } |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index c35336a0f71b..0cdd9a07e043 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include <linux/string.h> | 18 | #include <linux/string.h> |
19 | #include <linux/net.h> | 19 | #include <linux/net.h> |
20 | #include <linux/skbuff.h> | 20 | #include <linux/skbuff.h> |
21 | #include <linux/netlink.h> | ||
22 | #include <linux/rtnetlink.h> | 21 | #include <linux/rtnetlink.h> |
23 | #include <linux/pfkeyv2.h> | 22 | #include <linux/pfkeyv2.h> |
24 | #include <linux/ipsec.h> | 23 | #include <linux/ipsec.h> |
@@ -26,6 +25,7 @@ | |||
26 | #include <linux/security.h> | 25 | #include <linux/security.h> |
27 | #include <net/sock.h> | 26 | #include <net/sock.h> |
28 | #include <net/xfrm.h> | 27 | #include <net/xfrm.h> |
28 | #include <net/netlink.h> | ||
29 | #include <asm/uaccess.h> | 29 | #include <asm/uaccess.h> |
30 | 30 | ||
31 | static struct sock *xfrm_nl; | 31 | static struct sock *xfrm_nl; |
@@ -948,11 +948,6 @@ static struct xfrm_link { | |||
948 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy }, | 948 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy }, |
949 | }; | 949 | }; |
950 | 950 | ||
951 | static int xfrm_done(struct netlink_callback *cb) | ||
952 | { | ||
953 | return 0; | ||
954 | } | ||
955 | |||
956 | static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) | 951 | static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) |
957 | { | 952 | { |
958 | struct rtattr *xfrma[XFRMA_MAX]; | 953 | struct rtattr *xfrma[XFRMA_MAX]; |
@@ -984,20 +979,15 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *err | |||
984 | if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) || | 979 | if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) || |
985 | type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) && | 980 | type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) && |
986 | (nlh->nlmsg_flags & NLM_F_DUMP)) { | 981 | (nlh->nlmsg_flags & NLM_F_DUMP)) { |
987 | u32 rlen; | ||
988 | |||
989 | if (link->dump == NULL) | 982 | if (link->dump == NULL) |
990 | goto err_einval; | 983 | goto err_einval; |
991 | 984 | ||
992 | if ((*errp = netlink_dump_start(xfrm_nl, skb, nlh, | 985 | if ((*errp = netlink_dump_start(xfrm_nl, skb, nlh, |
993 | link->dump, | 986 | link->dump, NULL)) != 0) { |
994 | xfrm_done)) != 0) { | ||
995 | return -1; | 987 | return -1; |
996 | } | 988 | } |
997 | rlen = NLMSG_ALIGN(nlh->nlmsg_len); | 989 | |
998 | if (rlen > skb->len) | 990 | netlink_queue_skip(nlh, skb); |
999 | rlen = skb->len; | ||
1000 | skb_pull(skb, rlen); | ||
1001 | return -1; | 991 | return -1; |
1002 | } | 992 | } |
1003 | 993 | ||
@@ -1032,60 +1022,13 @@ err_einval: | |||
1032 | return -1; | 1022 | return -1; |
1033 | } | 1023 | } |
1034 | 1024 | ||
1035 | static int xfrm_user_rcv_skb(struct sk_buff *skb) | ||
1036 | { | ||
1037 | int err; | ||
1038 | struct nlmsghdr *nlh; | ||
1039 | |||
1040 | while (skb->len >= NLMSG_SPACE(0)) { | ||
1041 | u32 rlen; | ||
1042 | |||
1043 | nlh = (struct nlmsghdr *) skb->data; | ||
1044 | if (nlh->nlmsg_len < sizeof(*nlh) || | ||
1045 | skb->len < nlh->nlmsg_len) | ||
1046 | return 0; | ||
1047 | rlen = NLMSG_ALIGN(nlh->nlmsg_len); | ||
1048 | if (rlen > skb->len) | ||
1049 | rlen = skb->len; | ||
1050 | if (xfrm_user_rcv_msg(skb, nlh, &err) < 0) { | ||
1051 | if (err == 0) | ||
1052 | return -1; | ||
1053 | netlink_ack(skb, nlh, err); | ||
1054 | } else if (nlh->nlmsg_flags & NLM_F_ACK) | ||
1055 | netlink_ack(skb, nlh, 0); | ||
1056 | skb_pull(skb, rlen); | ||
1057 | } | ||
1058 | |||
1059 | return 0; | ||
1060 | } | ||
1061 | |||
1062 | static void xfrm_netlink_rcv(struct sock *sk, int len) | 1025 | static void xfrm_netlink_rcv(struct sock *sk, int len) |
1063 | { | 1026 | { |
1064 | unsigned int qlen = skb_queue_len(&sk->sk_receive_queue); | 1027 | unsigned int qlen = 0; |
1065 | 1028 | ||
1066 | do { | 1029 | do { |
1067 | struct sk_buff *skb; | ||
1068 | |||
1069 | down(&xfrm_cfg_sem); | 1030 | down(&xfrm_cfg_sem); |
1070 | 1031 | netlink_run_queue(sk, &qlen, &xfrm_user_rcv_msg); | |
1071 | if (qlen > skb_queue_len(&sk->sk_receive_queue)) | ||
1072 | qlen = skb_queue_len(&sk->sk_receive_queue); | ||
1073 | |||
1074 | for (; qlen; qlen--) { | ||
1075 | skb = skb_dequeue(&sk->sk_receive_queue); | ||
1076 | if (xfrm_user_rcv_skb(skb)) { | ||
1077 | if (skb->len) | ||
1078 | skb_queue_head(&sk->sk_receive_queue, | ||
1079 | skb); | ||
1080 | else { | ||
1081 | kfree_skb(skb); | ||
1082 | qlen--; | ||
1083 | } | ||
1084 | break; | ||
1085 | } | ||
1086 | kfree_skb(skb); | ||
1087 | } | ||
1088 | |||
1089 | up(&xfrm_cfg_sem); | 1032 | up(&xfrm_cfg_sem); |
1090 | 1033 | ||
1091 | } while (qlen); | 1034 | } while (qlen); |