diff options
93 files changed, 2876 insertions, 435 deletions
diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c index 51f430cc2fbf..2786f7c34b3f 100644 --- a/arch/arm/common/locomo.c +++ b/arch/arm/common/locomo.c @@ -541,6 +541,103 @@ locomo_init_one_child(struct locomo *lchip, struct locomo_dev_info *info) return ret; } +#ifdef CONFIG_PM + +struct locomo_save_data { + u16 LCM_GPO; + u16 LCM_SPICT; + u16 LCM_GPE; + u16 LCM_ASD; + u16 LCM_SPIMD; +}; + +static int locomo_suspend(struct device *dev, u32 pm_message_t, u32 level) +{ + struct locomo *lchip = dev_get_drvdata(dev); + struct locomo_save_data *save; + unsigned long flags; + + if (level != SUSPEND_DISABLE) + return 0; + + save = kmalloc(sizeof(struct locomo_save_data), GFP_KERNEL); + if (!save) + return -ENOMEM; + + dev->power.saved_state = (void *) save; + + spin_lock_irqsave(&lchip->lock, flags); + + save->LCM_GPO = locomo_readl(lchip->base + LOCOMO_GPO); /* GPIO */ + locomo_writel(0x00, lchip->base + LOCOMO_GPO); + save->LCM_SPICT = locomo_readl(lchip->base + LOCOMO_SPICT); /* SPI */ + locomo_writel(0x40, lchip->base + LOCOMO_SPICT); + save->LCM_GPE = locomo_readl(lchip->base + LOCOMO_GPE); /* GPIO */ + locomo_writel(0x00, lchip->base + LOCOMO_GPE); + save->LCM_ASD = locomo_readl(lchip->base + LOCOMO_ASD); /* ADSTART */ + locomo_writel(0x00, lchip->base + LOCOMO_ASD); + save->LCM_SPIMD = locomo_readl(lchip->base + LOCOMO_SPIMD); /* SPI */ + locomo_writel(0x3C14, lchip->base + LOCOMO_SPIMD); + + locomo_writel(0x00, lchip->base + LOCOMO_PAIF); + locomo_writel(0x00, lchip->base + LOCOMO_DAC); + locomo_writel(0x00, lchip->base + LOCOMO_BACKLIGHT + LOCOMO_TC); + + if ( (locomo_readl(lchip->base + LOCOMO_LED + LOCOMO_LPT0) & 0x88) && (locomo_readl(lchip->base + LOCOMO_LED + LOCOMO_LPT1) & 0x88) ) + locomo_writel(0x00, lchip->base + LOCOMO_C32K); /* CLK32 off */ + else + /* 18MHz already enabled, so no wait */ + locomo_writel(0xc1, lchip->base + LOCOMO_C32K); /* CLK32 on */ + + locomo_writel(0x00, lchip->base + LOCOMO_TADC); /* 18MHz clock off*/ + locomo_writel(0x00, lchip->base + LOCOMO_AUDIO + LOCOMO_ACC); /* 22MHz/24MHz clock off */ + locomo_writel(0x00, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS); /* FL */ + + spin_unlock_irqrestore(&lchip->lock, flags); + + return 0; +} + +static int locomo_resume(struct device *dev, u32 level) +{ + struct locomo *lchip = dev_get_drvdata(dev); + struct locomo_save_data *save; + unsigned long r; + unsigned long flags; + + if (level != RESUME_ENABLE) + return 0; + + save = (struct locomo_save_data *) dev->power.saved_state; + if (!save) + return 0; + + spin_lock_irqsave(&lchip->lock, flags); + + locomo_writel(save->LCM_GPO, lchip->base + LOCOMO_GPO); + locomo_writel(save->LCM_SPICT, lchip->base + LOCOMO_SPICT); + locomo_writel(save->LCM_GPE, lchip->base + LOCOMO_GPE); + locomo_writel(save->LCM_ASD, lchip->base + LOCOMO_ASD); + locomo_writel(save->LCM_SPIMD, lchip->base + LOCOMO_SPIMD); + + locomo_writel(0x00, lchip->base + LOCOMO_C32K); + locomo_writel(0x90, lchip->base + LOCOMO_TADC); + + locomo_writel(0, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KSC); + r = locomo_readl(lchip->base + LOCOMO_KEYBOARD + LOCOMO_KIC); + r &= 0xFEFF; + locomo_writel(r, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KIC); + locomo_writel(0x1, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KCMD); + + spin_unlock_irqrestore(&lchip->lock, flags); + + dev->power.saved_state = NULL; + kfree(save); + + return 0; +} +#endif + /** * locomo_probe - probe for a single LoCoMo chip. * @phys_addr: physical address of device. @@ -707,6 +804,10 @@ static struct device_driver locomo_device_driver = { .bus = &platform_bus_type, .probe = locomo_probe, .remove = locomo_remove, +#ifdef CONFIG_PM + .suspend = locomo_suspend, + .resume = locomo_resume, +#endif }; /* diff --git a/arch/arm/configs/s3c2410_defconfig b/arch/arm/configs/s3c2410_defconfig index 96a794d8de84..756348bf5170 100644 --- a/arch/arm/configs/s3c2410_defconfig +++ b/arch/arm/configs/s3c2410_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-git4 -# Wed Jun 22 15:56:42 2005 +# Linux kernel version: 2.6.13-git8 +# Thu Sep 8 19:24:02 2005 # CONFIG_ARM=y CONFIG_MMU=y @@ -22,6 +22,7 @@ CONFIG_INIT_ENV_ARG_LIMIT=32 # General setup # CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y # CONFIG_POSIX_MQUEUE is not set @@ -31,6 +32,7 @@ CONFIG_SYSCTL=y # CONFIG_HOTPLUG is not set CONFIG_KOBJECT_UEVENT=y # CONFIG_IKCONFIG is not set +CONFIG_INITRAMFS_SOURCE="" # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set @@ -88,7 +90,9 @@ CONFIG_ARCH_S3C2410=y # # S3C24XX Implementations # +CONFIG_MACH_ANUBIS=y CONFIG_ARCH_BAST=y +CONFIG_BAST_PC104_IRQ=y CONFIG_ARCH_H1940=y CONFIG_MACH_N30=y CONFIG_ARCH_SMDK2410=y @@ -112,6 +116,7 @@ CONFIG_S3C2410_DMA=y # CONFIG_S3C2410_DMA_DEBUG is not set # CONFIG_S3C2410_PM_DEBUG is not set # CONFIG_S3C2410_PM_CHECK is not set +CONFIG_PM_SIMTEC=y CONFIG_S3C2410_LOWLEVEL_UART_PORT=0 # @@ -149,7 +154,15 @@ CONFIG_ISA_DMA_API=y # # CONFIG_SMP is not set # CONFIG_PREEMPT is not set -# CONFIG_DISCONTIGMEM is not set +# CONFIG_NO_IDLE_HZ is not set +# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set CONFIG_ALIGNMENT_TRAP=y # @@ -186,6 +199,74 @@ CONFIG_PM=y CONFIG_APM=y # +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_PACKET is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETFILTER_NETLINK is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# # Device Drivers # @@ -258,6 +339,7 @@ CONFIG_MTD_ROM=y # CONFIG_MTD_IMPA7 is not set CONFIG_MTD_BAST=y CONFIG_MTD_BAST_MAXSIZE=4 +# CONFIG_MTD_PLATRAM is not set # # Self-contained MTD device drivers @@ -312,7 +394,6 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" # CONFIG_CDROM_PKTCDVD is not set # @@ -354,6 +435,7 @@ CONFIG_BLK_DEV_IDE_BAST=y # # SCSI device support # +# CONFIG_RAID_ATTRS is not set # CONFIG_SCSI is not set # @@ -376,70 +458,8 @@ CONFIG_BLK_DEV_IDE_BAST=y # # -# Networking support -# -CONFIG_NET=y - -# -# Networking options +# Network device support # -# CONFIG_PACKET is not set -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=y -CONFIG_IP_FIB_HASH=y -# CONFIG_IP_FIB_TRIE is not set -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_PNP=y -# CONFIG_IP_PNP_DHCP is not set -CONFIG_IP_PNP_BOOTP=y -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -# CONFIG_IP_TCPDIAG_IPV6 is not set -# CONFIG_IPV6 is not set -# CONFIG_NETFILTER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set @@ -447,6 +467,11 @@ CONFIG_NETDEVICES=y # CONFIG_TUN is not set # +# PHY device support +# +# CONFIG_PHYLIB is not set + +# # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y @@ -480,6 +505,8 @@ CONFIG_DM9000=m # CONFIG_SLIP is not set # CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set # # ISDN subsystem @@ -562,7 +589,6 @@ CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_SHARE_IRQ=y # CONFIG_SERIAL_8250_DETECT_IRQ is not set -# CONFIG_SERIAL_8250_MULTIPORT is not set # CONFIG_SERIAL_8250_RSA is not set # @@ -605,7 +631,6 @@ CONFIG_S3C2410_RTC=y # # Ftape, the floppy tape device driver # -# CONFIG_DRM is not set # CONFIG_RAW_DRIVER is not set # @@ -628,7 +653,7 @@ CONFIG_I2C_ALGOBIT=m # # I2C Hardware Bus support # -# CONFIG_I2C_ISA is not set +CONFIG_I2C_ISA=m # CONFIG_I2C_PARPORT is not set # CONFIG_I2C_PARPORT_LIGHT is not set CONFIG_I2C_S3C2410=y @@ -636,14 +661,33 @@ CONFIG_I2C_S3C2410=y # CONFIG_I2C_PCA_ISA is not set # -# Hardware Sensors Chip support +# Miscellaneous I2C Chip support # -CONFIG_I2C_SENSOR=m +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +CONFIG_SENSORS_EEPROM=m +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y +CONFIG_HWMON_VID=m # CONFIG_SENSORS_ADM1021 is not set # CONFIG_SENSORS_ADM1025 is not set # CONFIG_SENSORS_ADM1026 is not set # CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set # CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set # CONFIG_SENSORS_DS1621 is not set # CONFIG_SENSORS_FSCHER is not set # CONFIG_SENSORS_FSCPOS is not set @@ -662,27 +706,21 @@ CONFIG_SENSORS_LM85=m # CONFIG_SENSORS_LM92 is not set # CONFIG_SENSORS_MAX1619 is not set # CONFIG_SENSORS_PC87360 is not set -# CONFIG_SENSORS_SMSC47B397 is not set # CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47B397 is not set # CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83792D is not set # CONFIG_SENSORS_W83L785TS is not set # CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_HWMON_DEBUG_CHIP is not set # -# Other I2C Chip support +# Misc devices # -# CONFIG_SENSORS_DS1337 is not set -CONFIG_SENSORS_EEPROM=m -# CONFIG_SENSORS_PCF8574 is not set -# CONFIG_SENSORS_PCF8591 is not set -# CONFIG_SENSORS_RTC8564 is not set -# CONFIG_I2C_DEBUG_CORE is not set -# CONFIG_I2C_DEBUG_ALGO is not set -# CONFIG_I2C_DEBUG_BUS is not set -# CONFIG_I2C_DEBUG_CHIP is not set # -# Misc devices +# Multimedia Capabilities Port drivers # # @@ -731,7 +769,7 @@ CONFIG_DUMMY_CONSOLE=y # USB support # CONFIG_USB_ARCH_HAS_HCD=y -# CONFIG_USB_ARCH_HAS_OHCI is not set +CONFIG_USB_ARCH_HAS_OHCI=y # CONFIG_USB is not set # @@ -749,6 +787,7 @@ CONFIG_USB_ARCH_HAS_HCD=y # CONFIG_EXT2_FS=y # CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set CONFIG_EXT3_FS=y CONFIG_EXT3_FS_XATTR=y # CONFIG_EXT3_FS_POSIX_ACL is not set @@ -758,6 +797,7 @@ CONFIG_JBD=y CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set # # XFS support @@ -765,6 +805,7 @@ CONFIG_FS_MBCACHE=y # CONFIG_XFS_FS is not set # CONFIG_MINIX_FS is not set CONFIG_ROMFS_FS=y +CONFIG_INOTIFY=y # CONFIG_QUOTA is not set CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set @@ -791,11 +832,11 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_PROC_FS=y CONFIG_SYSFS=y -# CONFIG_DEVPTS_FS_XATTR is not set # CONFIG_TMPFS is not set # CONFIG_HUGETLBFS is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set # # Miscellaneous filesystems @@ -812,8 +853,7 @@ CONFIG_JFFS_FS_VERBOSE=0 # CONFIG_JFFS_PROC_FS is not set CONFIG_JFFS2_FS=y CONFIG_JFFS2_FS_DEBUG=0 -# CONFIG_JFFS2_FS_NAND is not set -# CONFIG_JFFS2_FS_NOR_ECC is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set CONFIG_JFFS2_ZLIB=y CONFIG_JFFS2_RTIME=y @@ -835,6 +875,7 @@ CONFIG_NFS_FS=y # CONFIG_NFSD is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set @@ -920,6 +961,7 @@ CONFIG_NLS_DEFAULT="iso8859-1" CONFIG_DEBUG_KERNEL=y # CONFIG_MAGIC_SYSRQ is not set CONFIG_LOG_BUF_SHIFT=16 +CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SPINLOCK is not set diff --git a/arch/arm/mach-clps7500/core.c b/arch/arm/mach-clps7500/core.c index 112f1d68fb2b..e216ab8b9e8f 100644 --- a/arch/arm/mach-clps7500/core.c +++ b/arch/arm/mach-clps7500/core.c @@ -354,7 +354,7 @@ static struct plat_serial8250_port serial_platform_data[] = { static struct platform_device serial_device = { .name = "serial8250", - .id = 0, + .id = PLAT8250_DEV_PLATFORM, .dev = { .platform_data = serial_platform_data, }, diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c index 23c4da10101b..5aeadfd72143 100644 --- a/arch/arm/mach-ebsa110/core.c +++ b/arch/arm/mach-ebsa110/core.c @@ -219,7 +219,7 @@ static struct plat_serial8250_port serial_platform_data[] = { static struct platform_device serial_device = { .name = "serial8250", - .id = 0, + .id = PLAT8250_DEV_PLATFORM, .dev = { .platform_data = serial_platform_data, }, diff --git a/arch/arm/mach-epxa10db/arch.c b/arch/arm/mach-epxa10db/arch.c index 7daa021676d0..44c56571d183 100644 --- a/arch/arm/mach-epxa10db/arch.c +++ b/arch/arm/mach-epxa10db/arch.c @@ -52,7 +52,7 @@ static struct plat_serial8250_port serial_platform_data[] = { static struct platform_device serial_device = { .name = "serial8250", - .id = 0, + .id = PLAT8250_DEV_PLATFORM, .dev = { .platform_data = serial_platform_data, }, diff --git a/arch/arm/mach-footbridge/isa.c b/arch/arm/mach-footbridge/isa.c index aa3a1fef563e..28846c7edaaf 100644 --- a/arch/arm/mach-footbridge/isa.c +++ b/arch/arm/mach-footbridge/isa.c @@ -34,7 +34,7 @@ static struct plat_serial8250_port serial_platform_data[] = { static struct platform_device serial_device = { .name = "serial8250", - .id = 0, + .id = PLAT8250_DEV_PLATFORM, .dev = { .platform_data = serial_platform_data, }, diff --git a/arch/arm/mach-h720x/cpu-h7202.c b/arch/arm/mach-h720x/cpu-h7202.c index 4b3199319e68..a4a7c0125d03 100644 --- a/arch/arm/mach-h720x/cpu-h7202.c +++ b/arch/arm/mach-h720x/cpu-h7202.c @@ -90,7 +90,7 @@ static struct plat_serial8250_port serial_platform_data[] = { static struct platform_device serial_device = { .name = "serial8250", - .id = 0, + .id = PLAT8250_DEV_PLATFORM, .dev = { .platform_data = serial_platform_data, }, diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c index 098c817a7fb8..74bd2fd602d4 100644 --- a/arch/arm/mach-ixp2000/core.c +++ b/arch/arm/mach-ixp2000/core.c @@ -174,7 +174,7 @@ static struct resource ixp2000_uart_resource = { static struct platform_device ixp2000_serial_device = { .name = "serial8250", - .id = 0, + .id = PLAT8250_DEV_PLATFORM, .dev = { .platform_data = ixp2000_serial_port, }, diff --git a/arch/arm/mach-ixp4xx/coyote-setup.c b/arch/arm/mach-ixp4xx/coyote-setup.c index 8b2f25322452..050c92768913 100644 --- a/arch/arm/mach-ixp4xx/coyote-setup.c +++ b/arch/arm/mach-ixp4xx/coyote-setup.c @@ -66,7 +66,7 @@ static struct plat_serial8250_port coyote_uart_data[] = { static struct platform_device coyote_uart = { .name = "serial8250", - .id = 0, + .id = PLAT8250_DEV_PLATFORM, .dev = { .platform_data = coyote_uart_data, }, diff --git a/arch/arm/mach-ixp4xx/gtwx5715-setup.c b/arch/arm/mach-ixp4xx/gtwx5715-setup.c index 3fd92c5cbaa8..29a6d02fa851 100644 --- a/arch/arm/mach-ixp4xx/gtwx5715-setup.c +++ b/arch/arm/mach-ixp4xx/gtwx5715-setup.c @@ -93,7 +93,7 @@ static struct plat_serial8250_port gtwx5715_uart_platform_data[] = { static struct platform_device gtwx5715_uart_device = { .name = "serial8250", - .id = 0, + .id = PLAT8250_DEV_PLATFORM, .dev = { .platform_data = gtwx5715_uart_platform_data, }, diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c index 6c14ff3c23a0..ae1fa099d5fa 100644 --- a/arch/arm/mach-ixp4xx/ixdp425-setup.c +++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c @@ -96,7 +96,7 @@ static struct plat_serial8250_port ixdp425_uart_data[] = { static struct platform_device ixdp425_uart = { .name = "serial8250", - .id = 0, + .id = PLAT8250_DEV_PLATFORM, .dev.platform_data = ixdp425_uart_data, .num_resources = 2, .resource = ixdp425_uart_resources diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig index 7408ac94f771..27fc2e8e5fca 100644 --- a/arch/arm/mach-omap1/Kconfig +++ b/arch/arm/mach-omap1/Kconfig @@ -47,6 +47,14 @@ config MACH_OMAP_OSK TI OMAP 5912 OSK (OMAP Starter Kit) board support. Say Y here if you have such a board. +config OMAP_OSK_MISTRAL + bool "Mistral QVGA board Support" + depends on MACH_OMAP_OSK + help + The OSK supports an optional add-on board with a Quarter-VGA + touchscreen, PDA-ish buttons, a resume button, bicolor LED, + and camera connector. Say Y here if you have this board. + config MACH_OMAP_PERSEUS2 bool "TI Perseus2" depends on ARCH_OMAP1 && ARCH_OMAP730 diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile index d386fd913f0c..181a93deaaee 100644 --- a/arch/arm/mach-omap1/Makefile +++ b/arch/arm/mach-omap1/Makefile @@ -3,7 +3,7 @@ # # Common support -obj-y := io.o id.o irq.o time.o serial.o +obj-y := io.o id.o irq.o time.o serial.o devices.o led-y := leds.o # Specific board support @@ -23,6 +23,7 @@ endif # LEDs support led-$(CONFIG_MACH_OMAP_H2) += leds-h2p2-debug.o +led-$(CONFIG_MACH_OMAP_H3) += leds-h2p2-debug.o led-$(CONFIG_MACH_OMAP_INNOVATOR) += leds-innovator.o led-$(CONFIG_MACH_OMAP_PERSEUS2) += leds-h2p2-debug.o led-$(CONFIG_MACH_OMAP_OSK) += leds-osk.o diff --git a/arch/arm/mach-omap1/board-generic.c b/arch/arm/mach-omap1/board-generic.c index 122796ebe8f5..c209c7172a9a 100644 --- a/arch/arm/mach-omap1/board-generic.c +++ b/arch/arm/mach-omap1/board-generic.c @@ -48,19 +48,43 @@ static struct omap_usb_config generic1510_usb_config __initdata = { #if defined(CONFIG_ARCH_OMAP16XX) static struct omap_usb_config generic1610_usb_config __initdata = { +#ifdef CONFIG_USB_OTG + .otg = 1, +#endif .register_host = 1, .register_dev = 1, .hmc_mode = 16, .pins[0] = 6, }; + +static struct omap_mmc_config generic_mmc_config __initdata = { + .mmc [0] = { + .enabled = 0, + .wire4 = 0, + .wp_pin = -1, + .power_pin = -1, + .switch_pin = -1, + }, + .mmc [1] = { + .enabled = 0, + .wire4 = 0, + .wp_pin = -1, + .power_pin = -1, + .switch_pin = -1, + }, +}; + #endif static struct omap_board_config_kernel generic_config[] = { { OMAP_TAG_USB, NULL }, + { OMAP_TAG_MMC, &generic_mmc_config }, }; static void __init omap_generic_init(void) { + const struct omap_uart_config *uart_conf; + /* * Make sure the serial ports are muxed on at this point. * You have to mux them off in device drivers later on @@ -76,6 +100,18 @@ static void __init omap_generic_init(void) generic_config[0].data = &generic1610_usb_config; } #endif + + uart_conf = omap_get_config(OMAP_TAG_UART, struct omap_uart_config); + if (uart_conf != NULL) { + unsigned int enabled_ports, i; + + enabled_ports = uart_conf->enabled_uarts; + for (i = 0; i < 3; i++) { + if (!(enabled_ports & (1 << i))) + generic_serial_ports[i] = 0; + } + } + omap_board_config = generic_config; omap_board_config_size = ARRAY_SIZE(generic_config); omap_serial_init(generic_serial_ports); @@ -83,7 +119,7 @@ static void __init omap_generic_init(void) static void __init omap_generic_map_io(void) { - omap_map_common_io() + omap_map_common_io(); } MACHINE_START(OMAP_GENERIC, "Generic OMAP1510/1610/1710") diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c index f4983ee95ab4..d46a70063b0c 100644 --- a/arch/arm/mach-omap1/board-h2.c +++ b/arch/arm/mach-omap1/board-h2.c @@ -33,6 +33,7 @@ #include <asm/mach/map.h> #include <asm/arch/gpio.h> +#include <asm/arch/mux.h> #include <asm/arch/tc.h> #include <asm/arch/usb.h> #include <asm/arch/common.h> @@ -80,8 +81,7 @@ static struct flash_platform_data h2_flash_data = { }; static struct resource h2_flash_resource = { - .start = OMAP_CS2B_PHYS, - .end = OMAP_CS2B_PHYS + OMAP_CS2B_SIZE - 1, + /* This is on CS3, wherever it's mapped */ .flags = IORESOURCE_MEM, }; @@ -126,10 +126,9 @@ static void __init h2_init_smc91x(void) printk("Error requesting gpio 0 for smc91x irq\n"); return; } - omap_set_gpio_edge_ctrl(0, OMAP_GPIO_FALLING_EDGE); } -void h2_init_irq(void) +static void __init h2_init_irq(void) { omap_init_irq(); omap_gpio_init(); @@ -152,9 +151,13 @@ static struct omap_usb_config h2_usb_config __initdata = { }; static struct omap_mmc_config h2_mmc_config __initdata = { - .mmc_blocks = 1, - .mmc1_power_pin = -1, /* tps65010 gpio3 */ - .mmc1_switch_pin = OMAP_MPUIO(1), + .mmc [0] = { + .enabled = 1, + .wire4 = 1, + .wp_pin = OMAP_MPUIO(3), + .power_pin = -1, /* tps65010 gpio3 */ + .switch_pin = OMAP_MPUIO(1), + }, }; static struct omap_board_config_kernel h2_config[] = { @@ -164,6 +167,16 @@ static struct omap_board_config_kernel h2_config[] = { static void __init h2_init(void) { + /* NOTE: revC boards support NAND-boot, which can put NOR on CS2B + * and NAND (either 16bit or 8bit) on CS3. + */ + h2_flash_resource.end = h2_flash_resource.start = omap_cs3_phys(); + h2_flash_resource.end += SZ_32M - 1; + + /* MMC: card detect and WP */ + // omap_cfg_reg(U19_ARMIO1); /* CD */ + omap_cfg_reg(BALLOUT_V8_ARMIO3); /* WP */ + platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices)); omap_board_config = h2_config; omap_board_config_size = ARRAY_SIZE(h2_config); diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c index 7cd419d61b40..2798613696fa 100644 --- a/arch/arm/mach-omap1/board-h3.c +++ b/arch/arm/mach-omap1/board-h3.c @@ -82,8 +82,7 @@ static struct flash_platform_data h3_flash_data = { }; static struct resource h3_flash_resource = { - .start = OMAP_CS2B_PHYS, - .end = OMAP_CS2B_PHYS + OMAP_CS2B_SIZE - 1, + /* This is on CS3, wherever it's mapped */ .flags = IORESOURCE_MEM, }; @@ -161,13 +160,26 @@ static struct omap_usb_config h3_usb_config __initdata = { .pins[1] = 3, }; +static struct omap_mmc_config h3_mmc_config __initdata = { + .mmc[0] = { + .enabled = 1, + .power_pin = -1, /* tps65010 GPIO4 */ + .switch_pin = OMAP_MPUIO(1), + }, +}; + static struct omap_board_config_kernel h3_config[] = { { OMAP_TAG_USB, &h3_usb_config }, + { OMAP_TAG_MMC, &h3_mmc_config }, }; static void __init h3_init(void) { + h3_flash_resource.end = h3_flash_resource.start = omap_cs3_phys(); + h3_flash_resource.end += OMAP_CS3_SIZE - 1; (void) platform_add_devices(devices, ARRAY_SIZE(devices)); + omap_board_config = h3_config; + omap_board_config_size = ARRAY_SIZE(h3_config); } static void __init h3_init_smc91x(void) @@ -177,7 +189,6 @@ static void __init h3_init_smc91x(void) printk("Error requesting gpio 40 for smc91x irq\n"); return; } - omap_set_gpio_edge_ctrl(40, OMAP_GPIO_FALLING_EDGE); } void h3_init_irq(void) diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c index 91de60a91ef8..df0312b596e4 100644 --- a/arch/arm/mach-omap1/board-innovator.c +++ b/arch/arm/mach-omap1/board-innovator.c @@ -29,6 +29,7 @@ #include <asm/mach/flash.h> #include <asm/mach/map.h> +#include <asm/arch/mux.h> #include <asm/arch/fpga.h> #include <asm/arch/gpio.h> #include <asm/arch/tc.h> @@ -173,7 +174,6 @@ static void __init innovator_init_smc91x(void) printk("Error requesting gpio 0 for smc91x irq\n"); return; } - omap_set_gpio_edge_ctrl(0, OMAP_GPIO_RISING_EDGE); } } @@ -220,8 +220,19 @@ static struct omap_usb_config h2_usb_config __initdata = { }; #endif +static struct omap_mmc_config innovator_mmc_config __initdata = { + .mmc [0] = { + .enabled = 1, + .wire4 = 1, + .wp_pin = OMAP_MPUIO(3), + .power_pin = -1, /* FPGA F3 UIO42 */ + .switch_pin = -1, /* FPGA F4 UIO43 */ + }, +}; + static struct omap_board_config_kernel innovator_config[] = { { OMAP_TAG_USB, NULL }, + { OMAP_TAG_MMC, &innovator_mmc_config }, }; static void __init innovator_init(void) diff --git a/arch/arm/mach-omap1/board-netstar.c b/arch/arm/mach-omap1/board-netstar.c index 6750b2014092..d904e643f5ec 100644 --- a/arch/arm/mach-omap1/board-netstar.c +++ b/arch/arm/mach-omap1/board-netstar.c @@ -75,16 +75,15 @@ static void __init netstar_init(void) mdelay(50); /* 50ms until PHY ready */ /* smc91x interrupt pin */ omap_request_gpio(8); - omap_set_gpio_edge_ctrl(8, OMAP_GPIO_RISING_EDGE); omap_request_gpio(12); omap_request_gpio(13); omap_request_gpio(14); omap_request_gpio(15); - omap_set_gpio_edge_ctrl(12, OMAP_GPIO_FALLING_EDGE); - omap_set_gpio_edge_ctrl(13, OMAP_GPIO_FALLING_EDGE); - omap_set_gpio_edge_ctrl(14, OMAP_GPIO_FALLING_EDGE); - omap_set_gpio_edge_ctrl(15, OMAP_GPIO_FALLING_EDGE); + set_irq_type(OMAP_GPIO_IRQ(12), IRQT_FALLING); + set_irq_type(OMAP_GPIO_IRQ(13), IRQT_FALLING); + set_irq_type(OMAP_GPIO_IRQ(14), IRQT_FALLING); + set_irq_type(OMAP_GPIO_IRQ(15), IRQT_FALLING); platform_add_devices(netstar_devices, ARRAY_SIZE(netstar_devices)); diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c index 6844e536c698..21103df50415 100644 --- a/arch/arm/mach-omap1/board-osk.c +++ b/arch/arm/mach-omap1/board-osk.c @@ -29,11 +29,16 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/device.h> +#include <linux/interrupt.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> #include <asm/hardware.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> +#include <asm/mach/flash.h> #include <asm/arch/gpio.h> #include <asm/arch/usb.h> @@ -41,12 +46,56 @@ #include <asm/arch/tc.h> #include <asm/arch/common.h> -static struct map_desc osk5912_io_desc[] __initdata = { -{ OMAP_OSK_NOR_FLASH_BASE, OMAP_OSK_NOR_FLASH_START, OMAP_OSK_NOR_FLASH_SIZE, - MT_DEVICE }, +static int __initdata osk_serial_ports[OMAP_MAX_NR_PORTS] = {1, 0, 0}; + +static struct mtd_partition osk_partitions[] = { + /* bootloader (U-Boot, etc) in first sector */ + { + .name = "bootloader", + .offset = 0, + .size = SZ_128K, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + /* bootloader params in the next sector */ + { + .name = "params", + .offset = MTDPART_OFS_APPEND, + .size = SZ_128K, + .mask_flags = 0, + }, { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = SZ_2M, + .mask_flags = 0 + }, { + .name = "filesystem", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + .mask_flags = 0 + } }; -static int __initdata osk_serial_ports[OMAP_MAX_NR_PORTS] = {1, 0, 0}; +static struct flash_platform_data osk_flash_data = { + .map_name = "cfi_probe", + .width = 2, + .parts = osk_partitions, + .nr_parts = ARRAY_SIZE(osk_partitions), +}; + +static struct resource osk_flash_resource = { + /* this is on CS3, wherever it's mapped */ + .flags = IORESOURCE_MEM, +}; + +static struct platform_device osk5912_flash_device = { + .name = "omapflash", + .id = 0, + .dev = { + .platform_data = &osk_flash_data, + }, + .num_resources = 1, + .resource = &osk_flash_resource, +}; static struct resource osk5912_smc91x_resources[] = { [0] = { @@ -86,9 +135,16 @@ static struct platform_device osk5912_cf_device = { .resource = osk5912_cf_resources, }; +static struct platform_device osk5912_mcbsp1_device = { + .name = "omap_mcbsp", + .id = 1, +}; + static struct platform_device *osk5912_devices[] __initdata = { + &osk5912_flash_device, &osk5912_smc91x_device, &osk5912_cf_device, + &osk5912_mcbsp1_device, }; static void __init osk_init_smc91x(void) @@ -97,7 +153,6 @@ static void __init osk_init_smc91x(void) printk("Error requesting gpio 0 for smc91x irq\n"); return; } - omap_set_gpio_edge_ctrl(0, OMAP_GPIO_RISING_EDGE); /* Check EMIFS wait states to fix errors with SMC_GET_PKT_HDR */ EMIFS_CCS(1) |= 0x2; @@ -110,11 +165,11 @@ static void __init osk_init_cf(void) printk("Error requesting gpio 62 for CF irq\n"); return; } - /* it's really active-low */ - omap_set_gpio_edge_ctrl(62, OMAP_GPIO_FALLING_EDGE); + /* the CF I/O IRQ is really active-low */ + set_irq_type(OMAP_GPIO_IRQ(62), IRQT_FALLING); } -void osk_init_irq(void) +static void __init osk_init_irq(void) { omap_init_irq(); omap_gpio_init(); @@ -142,18 +197,69 @@ static struct omap_board_config_kernel osk_config[] = { { OMAP_TAG_USB, &osk_usb_config }, }; +#ifdef CONFIG_OMAP_OSK_MISTRAL + +#ifdef CONFIG_PM +static irqreturn_t +osk_mistral_wake_interrupt(int irq, void *ignored, struct pt_regs *regs) +{ + return IRQ_HANDLED; +} +#endif + +static void __init osk_mistral_init(void) +{ + /* FIXME here's where to feed in framebuffer, touchpad, and + * keyboard setup ... not in the drivers for those devices! + * + * NOTE: we could actually tell if there's a Mistral board + * attached, e.g. by trying to read something from the ads7846. + * But this is too early for that... + */ + + /* the sideways button (SW1) is for use as a "wakeup" button */ + omap_cfg_reg(N15_1610_MPUIO2); + if (omap_request_gpio(OMAP_MPUIO(2)) == 0) { + int ret = 0; + omap_set_gpio_direction(OMAP_MPUIO(2), 1); + set_irq_type(OMAP_GPIO_IRQ(OMAP_MPUIO(2)), IRQT_RISING); +#ifdef CONFIG_PM + /* share the IRQ in case someone wants to use the + * button for more than wakeup from system sleep. + */ + ret = request_irq(OMAP_GPIO_IRQ(OMAP_MPUIO(2)), + &osk_mistral_wake_interrupt, + SA_SHIRQ, "mistral_wakeup", + &osk_mistral_wake_interrupt); + if (ret != 0) { + omap_free_gpio(OMAP_MPUIO(2)); + printk(KERN_ERR "OSK+Mistral: no wakeup irq, %d?\n", + ret); + } else + enable_irq_wake(OMAP_GPIO_IRQ(OMAP_MPUIO(2))); +#endif + } else + printk(KERN_ERR "OSK+Mistral: wakeup button is awol\n"); +} +#else +static void __init osk_mistral_init(void) { } +#endif + static void __init osk_init(void) { + osk_flash_resource.end = osk_flash_resource.start = omap_cs3_phys(); + osk_flash_resource.end += SZ_32M - 1; platform_add_devices(osk5912_devices, ARRAY_SIZE(osk5912_devices)); omap_board_config = osk_config; omap_board_config_size = ARRAY_SIZE(osk_config); USB_TRANSCEIVER_CTRL_REG |= (3 << 1); + + osk_mistral_init(); } static void __init osk_map_io(void) { omap_map_common_io(); - iotable_init(osk5912_io_desc, ARRAY_SIZE(osk5912_io_desc)); omap_serial_init(osk_serial_ports); } diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c index 213317392d9b..107c68c8ab54 100644 --- a/arch/arm/mach-omap1/board-perseus2.c +++ b/arch/arm/mach-omap1/board-perseus2.c @@ -24,6 +24,7 @@ #include <asm/mach/flash.h> #include <asm/mach/map.h> +#include <asm/arch/tc.h> #include <asm/arch/gpio.h> #include <asm/arch/mux.h> #include <asm/arch/fpga.h> @@ -83,8 +84,8 @@ static struct flash_platform_data p2_flash_data = { }; static struct resource p2_flash_resource = { - .start = OMAP_FLASH_0_START, - .end = OMAP_FLASH_0_START + OMAP_FLASH_0_SIZE - 1, + .start = OMAP_CS0_PHYS, + .end = OMAP_CS0_PHYS + SZ_32M - 1, .flags = IORESOURCE_MEM, }; diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c index e42281988990..bf30b1acda0b 100644 --- a/arch/arm/mach-omap1/board-voiceblue.c +++ b/arch/arm/mach-omap1/board-voiceblue.c @@ -25,13 +25,14 @@ #include <asm/hardware.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> +#include <asm/mach/flash.h> #include <asm/mach/map.h> +#include <asm/arch/common.h> #include <asm/arch/gpio.h> -#include <asm/arch/tc.h> #include <asm/arch/mux.h> +#include <asm/arch/tc.h> #include <asm/arch/usb.h> -#include <asm/arch/common.h> extern void omap_init_time(void); extern int omap_gpio_init(void); @@ -74,7 +75,7 @@ static struct plat_serial8250_port voiceblue_ports[] = { static struct platform_device serial_device = { .name = "serial8250", - .id = 1, + .id = PLAT8250_DEV_PLATFORM1, .dev = { .platform_data = voiceblue_ports, }, @@ -86,6 +87,27 @@ static int __init ext_uart_init(void) } arch_initcall(ext_uart_init); +static struct flash_platform_data voiceblue_flash_data = { + .map_name = "cfi_probe", + .width = 2, +}; + +static struct resource voiceblue_flash_resource = { + .start = OMAP_CS0_PHYS, + .end = OMAP_CS0_PHYS + SZ_32M - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device voiceblue_flash_device = { + .name = "omapflash", + .id = 0, + .dev = { + .platform_data = &voiceblue_flash_data, + }, + .num_resources = 1, + .resource = &voiceblue_flash_resource, +}; + static struct resource voiceblue_smc91x_resources[] = { [0] = { .start = OMAP_CS2_PHYS + 0x300, @@ -107,6 +129,7 @@ static struct platform_device voiceblue_smc91x_device = { }; static struct platform_device *voiceblue_devices[] __initdata = { + &voiceblue_flash_device, &voiceblue_smc91x_device, }; @@ -119,8 +142,17 @@ static struct omap_usb_config voiceblue_usb_config __initdata = { .pins[2] = 6, }; +static struct omap_mmc_config voiceblue_mmc_config __initdata = { + .mmc[0] = { + .enabled = 1, + .power_pin = 2, + .switch_pin = -1, + }, +}; + static struct omap_board_config_kernel voiceblue_config[] = { { OMAP_TAG_USB, &voiceblue_usb_config }, + { OMAP_TAG_MMC, &voiceblue_mmc_config }, }; static void __init voiceblue_init_irq(void) @@ -131,9 +163,6 @@ static void __init voiceblue_init_irq(void) static void __init voiceblue_init(void) { - /* There is a good chance board is going up, so enable Power LED - * (it is connected through invertor) */ - omap_writeb(0x00, OMAP_LPG1_LCR); /* Watchdog */ omap_request_gpio(0); /* smc91x reset */ @@ -145,7 +174,6 @@ static void __init voiceblue_init(void) mdelay(50); /* 50ms until PHY ready */ /* smc91x interrupt pin */ omap_request_gpio(8); - omap_set_gpio_edge_ctrl(8, OMAP_GPIO_RISING_EDGE); /* 16C554 reset*/ omap_request_gpio(6); omap_set_gpio_direction(6, 0); @@ -155,14 +183,19 @@ static void __init voiceblue_init(void) omap_request_gpio(13); omap_request_gpio(14); omap_request_gpio(15); - omap_set_gpio_edge_ctrl(12, OMAP_GPIO_RISING_EDGE); - omap_set_gpio_edge_ctrl(13, OMAP_GPIO_RISING_EDGE); - omap_set_gpio_edge_ctrl(14, OMAP_GPIO_RISING_EDGE); - omap_set_gpio_edge_ctrl(15, OMAP_GPIO_RISING_EDGE); + set_irq_type(OMAP_GPIO_IRQ(12), IRQT_RISING); + set_irq_type(OMAP_GPIO_IRQ(13), IRQT_RISING); + set_irq_type(OMAP_GPIO_IRQ(14), IRQT_RISING); + set_irq_type(OMAP_GPIO_IRQ(15), IRQT_RISING); platform_add_devices(voiceblue_devices, ARRAY_SIZE(voiceblue_devices)); omap_board_config = voiceblue_config; omap_board_config_size = ARRAY_SIZE(voiceblue_config); + + /* There is a good chance board is going up, so enable power LED + * (it is connected through invertor) */ + omap_writeb(0x00, OMAP_LPG1_LCR); + omap_writeb(0x00, OMAP_LPG1_PMR); /* Disable clock */ } static int __initdata omap_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1}; @@ -184,9 +217,9 @@ static int panic_event(struct notifier_block *this, unsigned long event, if (test_and_set_bit(MACHINE_PANICED, &machine_state)) return NOTIFY_DONE; - /* Flash Power LED - * (TODO: Enable clock right way (enabled in bootloader already)) */ + /* Flash power LED */ omap_writeb(0x78, OMAP_LPG1_LCR); + omap_writeb(0x01, OMAP_LPG1_PMR); /* Enable clock */ return NOTIFY_DONE; } @@ -195,15 +228,14 @@ static struct notifier_block panic_block = { .notifier_call = panic_event, }; -static int __init setup_notifier(void) +static int __init voiceblue_setup(void) { /* Setup panic notifier */ notifier_chain_register(&panic_notifier_list, &panic_block); return 0; } - -postcore_initcall(setup_notifier); +postcore_initcall(voiceblue_setup); static int wdt_gpio_state; diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c new file mode 100644 index 000000000000..e8b3981444cd --- /dev/null +++ b/arch/arm/mach-omap1/devices.c @@ -0,0 +1,351 @@ +/* + * linux/arch/arm/mach-omap1/devices.c + * + * OMAP1 platform device setup/initialization + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/device.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/mach-types.h> +#include <asm/mach/map.h> + +#include <asm/arch/tc.h> +#include <asm/arch/board.h> +#include <asm/arch/mux.h> +#include <asm/arch/gpio.h> + + +static void omap_nop_release(struct device *dev) +{ + /* Nothing */ +} + +/*-------------------------------------------------------------------------*/ + +#if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE) + +#define OMAP_I2C_BASE 0xfffb3800 + +static struct resource i2c_resources[] = { + { + .start = OMAP_I2C_BASE, + .end = OMAP_I2C_BASE + 0x3f, + .flags = IORESOURCE_MEM, + }, + { + .start = INT_I2C, + .flags = IORESOURCE_IRQ, + }, +}; + +/* DMA not used; works around erratum writing to non-empty i2c fifo */ + +static struct platform_device omap_i2c_device = { + .name = "i2c_omap", + .id = -1, + .dev = { + .release = omap_nop_release, + }, + .num_resources = ARRAY_SIZE(i2c_resources), + .resource = i2c_resources, +}; + +static void omap_init_i2c(void) +{ + /* FIXME define and use a boot tag, in case of boards that + * either don't wire up I2C, or chips that mux it differently... + * it can include clocking and address info, maybe more. + */ + omap_cfg_reg(I2C_SCL); + omap_cfg_reg(I2C_SDA); + + (void) platform_device_register(&omap_i2c_device); +} +#else +static inline void omap_init_i2c(void) {} +#endif + +/*-------------------------------------------------------------------------*/ + +#if defined(CONFIG_OMAP1610_IR) || defined(CONFIG_OMAP161O_IR_MODULE) + +static u64 irda_dmamask = 0xffffffff; + +static struct platform_device omap1610ir_device = { + .name = "omap1610-ir", + .id = -1, + .dev = { + .release = omap_nop_release, + .dma_mask = &irda_dmamask, + }, +}; + +static void omap_init_irda(void) +{ + /* FIXME define and use a boot tag, members something like: + * u8 uart; // uart1, or uart3 + * ... but driver only handles uart3 for now + * s16 fir_sel; // gpio for SIR vs FIR + * ... may prefer a callback for SIR/MIR/FIR mode select; + * while h2 uses a GPIO, H3 uses a gpio expander + */ + if (machine_is_omap_h2() + || machine_is_omap_h3()) + (void) platform_device_register(&omap1610ir_device); +} +#else +static inline void omap_init_irda(void) {} +#endif + +/*-------------------------------------------------------------------------*/ + +#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) + +#define OMAP_MMC1_BASE 0xfffb7800 +#define OMAP_MMC2_BASE 0xfffb7c00 /* omap16xx only */ + +static struct omap_mmc_conf mmc1_conf; + +static u64 mmc1_dmamask = 0xffffffff; + +static struct resource mmc1_resources[] = { + { + .start = IO_ADDRESS(OMAP_MMC1_BASE), + .end = IO_ADDRESS(OMAP_MMC1_BASE) + 0x7f, + .flags = IORESOURCE_MEM, + }, + { + .start = INT_MMC, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device mmc_omap_device1 = { + .name = "mmci-omap", + .id = 1, + .dev = { + .release = omap_nop_release, + .dma_mask = &mmc1_dmamask, + .platform_data = &mmc1_conf, + }, + .num_resources = ARRAY_SIZE(mmc1_resources), + .resource = mmc1_resources, +}; + +#ifdef CONFIG_ARCH_OMAP16XX + +static struct omap_mmc_conf mmc2_conf; + +static u64 mmc2_dmamask = 0xffffffff; + +static struct resource mmc2_resources[] = { + { + .start = IO_ADDRESS(OMAP_MMC2_BASE), + .end = IO_ADDRESS(OMAP_MMC2_BASE) + 0x7f, + .flags = IORESOURCE_MEM, + }, + { + .start = INT_1610_MMC2, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device mmc_omap_device2 = { + .name = "mmci-omap", + .id = 2, + .dev = { + .release = omap_nop_release, + .dma_mask = &mmc2_dmamask, + .platform_data = &mmc2_conf, + }, + .num_resources = ARRAY_SIZE(mmc2_resources), + .resource = mmc2_resources, +}; +#endif + +static void __init omap_init_mmc(void) +{ + const struct omap_mmc_config *mmc_conf; + const struct omap_mmc_conf *mmc; + + /* NOTE: assumes MMC was never (wrongly) enabled */ + mmc_conf = omap_get_config(OMAP_TAG_MMC, struct omap_mmc_config); + if (!mmc_conf) + return; + + /* block 1 is always available and has just one pinout option */ + mmc = &mmc_conf->mmc[0]; + if (mmc->enabled) { + omap_cfg_reg(MMC_CMD); + omap_cfg_reg(MMC_CLK); + omap_cfg_reg(MMC_DAT0); + if (cpu_is_omap1710()) { + omap_cfg_reg(M15_1710_MMC_CLKI); + omap_cfg_reg(P19_1710_MMC_CMDDIR); + omap_cfg_reg(P20_1710_MMC_DATDIR0); + } + if (mmc->wire4) { + omap_cfg_reg(MMC_DAT1); + /* NOTE: DAT2 can be on W10 (here) or M15 */ + if (!mmc->nomux) + omap_cfg_reg(MMC_DAT2); + omap_cfg_reg(MMC_DAT3); + } + mmc1_conf = *mmc; + (void) platform_device_register(&mmc_omap_device1); + } + +#ifdef CONFIG_ARCH_OMAP16XX + /* block 2 is on newer chips, and has many pinout options */ + mmc = &mmc_conf->mmc[1]; + if (mmc->enabled) { + if (!mmc->nomux) { + omap_cfg_reg(Y8_1610_MMC2_CMD); + omap_cfg_reg(Y10_1610_MMC2_CLK); + omap_cfg_reg(R18_1610_MMC2_CLKIN); + omap_cfg_reg(W8_1610_MMC2_DAT0); + if (mmc->wire4) { + omap_cfg_reg(V8_1610_MMC2_DAT1); + omap_cfg_reg(W15_1610_MMC2_DAT2); + omap_cfg_reg(R10_1610_MMC2_DAT3); + } + + /* These are needed for the level shifter */ + omap_cfg_reg(V9_1610_MMC2_CMDDIR); + omap_cfg_reg(V5_1610_MMC2_DATDIR0); + omap_cfg_reg(W19_1610_MMC2_DATDIR1); + } + + /* Feedback clock must be set on OMAP-1710 MMC2 */ + if (cpu_is_omap1710()) + omap_writel(omap_readl(MOD_CONF_CTRL_1) | (1 << 24), + MOD_CONF_CTRL_1); + mmc2_conf = *mmc; + (void) platform_device_register(&mmc_omap_device2); + } +#endif + return; +} +#else +static inline void omap_init_mmc(void) {} +#endif + +#if defined(CONFIG_OMAP_RTC) || defined(CONFIG_OMAP_RTC) + +#define OMAP_RTC_BASE 0xfffb4800 + +static struct resource rtc_resources[] = { + { + .start = OMAP_RTC_BASE, + .end = OMAP_RTC_BASE + 0x5f, + .flags = IORESOURCE_MEM, + }, + { + .start = INT_RTC_TIMER, + .flags = IORESOURCE_IRQ, + }, + { + .start = INT_RTC_ALARM, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device omap_rtc_device = { + .name = "omap_rtc", + .id = -1, + .dev = { + .release = omap_nop_release, + }, + .num_resources = ARRAY_SIZE(rtc_resources), + .resource = rtc_resources, +}; + +static void omap_init_rtc(void) +{ + (void) platform_device_register(&omap_rtc_device); +} +#else +static inline void omap_init_rtc(void) {} +#endif + +/*-------------------------------------------------------------------------*/ + +#if defined(CONFIG_OMAP16XX_WATCHDOG) || defined(CONFIG_OMAP16XX_WATCHDOG_MODULE) + +#define OMAP_WDT_BASE 0xfffeb000 + +static struct resource wdt_resources[] = { + { + .start = OMAP_WDT_BASE, + .end = OMAP_WDT_BASE + 0x4f, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device omap_wdt_device = { + .name = "omap1610_wdt", + .id = -1, + .dev = { + .release = omap_nop_release, + }, + .num_resources = ARRAY_SIZE(wdt_resources), + .resource = wdt_resources, +}; + +static void omap_init_wdt(void) +{ + (void) platform_device_register(&omap_wdt_device); +} +#else +static inline void omap_init_wdt(void) {} +#endif + + +/*-------------------------------------------------------------------------*/ + +/* + * This gets called after board-specific INIT_MACHINE, and initializes most + * on-chip peripherals accessible on this board (except for few like USB): + * + * (a) Does any "standard config" pin muxing needed. Board-specific + * code will have muxed GPIO pins and done "nonstandard" setup; + * that code could live in the boot loader. + * (b) Populating board-specific platform_data with the data drivers + * rely on to handle wiring variations. + * (c) Creating platform devices as meaningful on this board and + * with this kernel configuration. + * + * Claiming GPIOs, and setting their direction and initial values, is the + * responsibility of the device drivers. So is responding to probe(). + * + * Board-specific knowlege like creating devices or pin setup is to be + * kept out of drivers as much as possible. In particular, pin setup + * may be handled by the boot loader, and drivers should expect it will + * normally have been done by the time they're probed. + */ +static int __init omap_init_devices(void) +{ + /* please keep these calls, and their implementations above, + * in alphabetical order so they're easier to sort through. + */ + omap_init_i2c(); + omap_init_irda(); + omap_init_mmc(); + omap_init_rtc(); + omap_init_wdt(); + + return 0; +} +arch_initcall(omap_init_devices); + diff --git a/arch/arm/mach-omap1/fpga.c b/arch/arm/mach-omap1/fpga.c index c12a78335625..aca2a120813a 100644 --- a/arch/arm/mach-omap1/fpga.c +++ b/arch/arm/mach-omap1/fpga.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/fpga.c + * linux/arch/arm/mach-omap1/fpga.c * * Interrupt handler for OMAP-1510 Innovator FPGA * @@ -181,7 +181,7 @@ void omap1510_fpga_init_irq(void) */ omap_request_gpio(13); omap_set_gpio_direction(13, 1); - omap_set_gpio_edge_ctrl(13, OMAP_GPIO_RISING_EDGE); + set_irq_type(OMAP_GPIO_IRQ(13), IRQT_RISING); set_irq_chained_handler(OMAP1510_INT_FPGA, innovator_fpga_IRQ_demux); } diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c index 207df0fe934d..eb8261d7dead 100644 --- a/arch/arm/mach-omap1/io.c +++ b/arch/arm/mach-omap1/io.c @@ -19,6 +19,7 @@ extern int clk_init(void); extern void omap_check_revision(void); +extern void omap_sram_init(void); /* * The machine specific code may provide the extra mapping besides the @@ -32,7 +33,6 @@ static struct map_desc omap_io_desc[] __initdata = { static struct map_desc omap730_io_desc[] __initdata = { { OMAP730_DSP_BASE, OMAP730_DSP_START, OMAP730_DSP_SIZE, MT_DEVICE }, { OMAP730_DSPREG_BASE, OMAP730_DSPREG_START, OMAP730_DSPREG_SIZE, MT_DEVICE }, - { OMAP730_SRAM_BASE, OMAP730_SRAM_START, OMAP730_SRAM_SIZE, MT_DEVICE } }; #endif @@ -40,27 +40,13 @@ static struct map_desc omap730_io_desc[] __initdata = { static struct map_desc omap1510_io_desc[] __initdata = { { OMAP1510_DSP_BASE, OMAP1510_DSP_START, OMAP1510_DSP_SIZE, MT_DEVICE }, { OMAP1510_DSPREG_BASE, OMAP1510_DSPREG_START, OMAP1510_DSPREG_SIZE, MT_DEVICE }, - { OMAP1510_SRAM_BASE, OMAP1510_SRAM_START, OMAP1510_SRAM_SIZE, MT_DEVICE } }; #endif #if defined(CONFIG_ARCH_OMAP16XX) -static struct map_desc omap1610_io_desc[] __initdata = { +static struct map_desc omap16xx_io_desc[] __initdata = { { OMAP16XX_DSP_BASE, OMAP16XX_DSP_START, OMAP16XX_DSP_SIZE, MT_DEVICE }, { OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_START, OMAP16XX_DSPREG_SIZE, MT_DEVICE }, - { OMAP16XX_SRAM_BASE, OMAP16XX_SRAM_START, OMAP1610_SRAM_SIZE, MT_DEVICE } -}; - -static struct map_desc omap5912_io_desc[] __initdata = { - { OMAP16XX_DSP_BASE, OMAP16XX_DSP_START, OMAP16XX_DSP_SIZE, MT_DEVICE }, - { OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_START, OMAP16XX_DSPREG_SIZE, MT_DEVICE }, -/* - * The OMAP5912 has 250kByte internal SRAM. Because the mapping is baseed on page - * size (4kByte), it seems that the last 2kByte (=0x800) of the 250kByte are not mapped. - * Add additional 2kByte (0x800) so that the last page is mapped and the last 2kByte - * can be used. - */ - { OMAP16XX_SRAM_BASE, OMAP16XX_SRAM_START, OMAP5912_SRAM_SIZE + 0x800, MT_DEVICE } }; #endif @@ -86,14 +72,13 @@ static void __init _omap_map_io(void) } #endif #if defined(CONFIG_ARCH_OMAP16XX) - if (cpu_is_omap1610() || cpu_is_omap1710()) { - iotable_init(omap1610_io_desc, ARRAY_SIZE(omap1610_io_desc)); - } - if (cpu_is_omap5912()) { - iotable_init(omap5912_io_desc, ARRAY_SIZE(omap5912_io_desc)); + if (cpu_is_omap16xx()) { + iotable_init(omap16xx_io_desc, ARRAY_SIZE(omap16xx_io_desc)); } #endif + omap_sram_init(); + /* REVISIT: Refer to OMAP5910 Errata, Advisory SYS_1: "Timeout Abort * on a Posted Write in the TIPB Bridge". */ @@ -108,8 +93,9 @@ static void __init _omap_map_io(void) /* * This should only get called from board specific init */ -void omap_map_common_io(void) +void __init omap_map_common_io(void) { if (!initialized) _omap_map_io(); } + diff --git a/arch/arm/mach-omap1/irq.c b/arch/arm/mach-omap1/irq.c index afd5d67e4ae7..192ce6055faa 100644 --- a/arch/arm/mach-omap1/irq.c +++ b/arch/arm/mach-omap1/irq.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/irq.c + * linux/arch/arm/mach-omap1/irq.c * * Interrupt handler for all OMAP boards * diff --git a/arch/arm/mach-omap1/leds-h2p2-debug.c b/arch/arm/mach-omap1/leds-h2p2-debug.c index ec0d8285f243..be283cda63dd 100644 --- a/arch/arm/mach-omap1/leds-h2p2-debug.c +++ b/arch/arm/mach-omap1/leds-h2p2-debug.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/leds-h2p2-debug.c + * linux/arch/arm/mach-omap1/leds-h2p2-debug.c * * Copyright 2003 by Texas Instruments Incorporated * @@ -13,6 +13,7 @@ #include <linux/init.h> #include <linux/kernel_stat.h> #include <linux/sched.h> +#include <linux/version.h> #include <asm/io.h> #include <asm/hardware.h> diff --git a/arch/arm/mach-omap1/leds-innovator.c b/arch/arm/mach-omap1/leds-innovator.c index 8043b7d0f66e..c8ffd1ddcded 100644 --- a/arch/arm/mach-omap1/leds-innovator.c +++ b/arch/arm/mach-omap1/leds-innovator.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/leds-innovator.c + * linux/arch/arm/mach-omap1/leds-innovator.c */ #include <linux/config.h> #include <linux/init.h> diff --git a/arch/arm/mach-omap1/leds-osk.c b/arch/arm/mach-omap1/leds-osk.c index 4a0e8b9d4fc3..2c8bda847c18 100644 --- a/arch/arm/mach-omap1/leds-osk.c +++ b/arch/arm/mach-omap1/leds-osk.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/leds-osk.c + * linux/arch/arm/mach-omap1/leds-osk.c * * LED driver for OSK, and optionally Mistral QVGA, boards */ @@ -64,7 +64,7 @@ static void tps_work(void *unused) static DECLARE_WORK(work, tps_work, NULL); -#ifdef CONFIG_FB_OMAP +#ifdef CONFIG_OMAP_OSK_MISTRAL /* For now, all system indicators require the Mistral board, since that * LED can be manipulated without a task context. This LED is either red, @@ -127,7 +127,7 @@ void osk_leds_event(led_event_t evt) hw_led_state = 0; break; -#ifdef CONFIG_FB_OMAP +#ifdef CONFIG_OMAP_OSK_MISTRAL case led_timer: hw_led_state ^= TIMER_LED; @@ -144,7 +144,7 @@ void osk_leds_event(led_event_t evt) mistral_setled(); break; -#endif /* CONFIG_FB_OMAP */ +#endif /* CONFIG_OMAP_OSK_MISTRAL */ /* "green" == tps LED1 (leftmost, normally power-good) * works only with DC adapter, not on battery power! diff --git a/arch/arm/mach-omap1/leds.c b/arch/arm/mach-omap1/leds.c index 8ab21fe98e1b..5c6b1bb6e722 100644 --- a/arch/arm/mach-omap1/leds.c +++ b/arch/arm/mach-omap1/leds.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/leds.c + * linux/arch/arm/mach-omap1/leds.c * * OMAP LEDs dispatcher */ @@ -20,7 +20,9 @@ omap_leds_init(void) if (machine_is_omap_innovator()) leds_event = innovator_leds_event; - else if (machine_is_omap_h2() || machine_is_omap_perseus2()) + else if (machine_is_omap_h2() + || machine_is_omap_h3() + || machine_is_omap_perseus2()) leds_event = h2p2_dbg_leds_event; else if (machine_is_omap_osk()) @@ -30,8 +32,12 @@ omap_leds_init(void) return -1; if (machine_is_omap_h2() + || machine_is_omap_h3() || machine_is_omap_perseus2() - || machine_is_omap_osk()) { +#ifdef CONFIG_OMAP_OSK_MISTRAL + || machine_is_omap_osk() +#endif + ) { /* LED1/LED2 pins can be used as GPIO (as done here), or by * the LPG (works even in deep sleep!), to drive a bicolor diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c index 214e5d17c8b5..40c4f7c40e73 100644 --- a/arch/arm/mach-omap1/serial.c +++ b/arch/arm/mach-omap1/serial.c @@ -24,7 +24,11 @@ #include <asm/arch/board.h> #include <asm/arch/mux.h> +#include <asm/arch/gpio.h> #include <asm/arch/fpga.h> +#ifdef CONFIG_PM +#include <asm/arch/pm.h> +#endif static struct clk * uart1_ck = NULL; static struct clk * uart2_ck = NULL; @@ -94,7 +98,7 @@ static struct plat_serial8250_port serial_platform_data[] = { static struct platform_device serial_device = { .name = "serial8250", - .id = 0, + .id = PLAT8250_DEV_PLATFORM, .dev = { .platform_data = serial_platform_data, }, @@ -193,6 +197,86 @@ void __init omap_serial_init(int ports[OMAP_MAX_NR_PORTS]) } } +#ifdef CONFIG_OMAP_SERIAL_WAKE + +static irqreturn_t omap_serial_wake_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + /* Need to do something with serial port right after wake-up? */ + return IRQ_HANDLED; +} + +/* + * Reroutes serial RX lines to GPIO lines for the duration of + * sleep to allow waking up the device from serial port even + * in deep sleep. + */ +void omap_serial_wake_trigger(int enable) +{ + if (!cpu_is_omap16xx()) + return; + + if (uart1_ck != NULL) { + if (enable) + omap_cfg_reg(V14_16XX_GPIO37); + else + omap_cfg_reg(V14_16XX_UART1_RX); + } + if (uart2_ck != NULL) { + if (enable) + omap_cfg_reg(R9_16XX_GPIO18); + else + omap_cfg_reg(R9_16XX_UART2_RX); + } + if (uart3_ck != NULL) { + if (enable) + omap_cfg_reg(L14_16XX_GPIO49); + else + omap_cfg_reg(L14_16XX_UART3_RX); + } +} + +static void __init omap_serial_set_port_wakeup(int gpio_nr) +{ + int ret; + + ret = omap_request_gpio(gpio_nr); + if (ret < 0) { + printk(KERN_ERR "Could not request UART wake GPIO: %i\n", + gpio_nr); + return; + } + omap_set_gpio_direction(gpio_nr, 1); + set_irq_type(OMAP_GPIO_IRQ(gpio_nr), IRQT_RISING); + ret = request_irq(OMAP_GPIO_IRQ(gpio_nr), &omap_serial_wake_interrupt, + 0, "serial wakeup", NULL); + if (ret) { + omap_free_gpio(gpio_nr); + printk(KERN_ERR "No interrupt for UART wake GPIO: %i\n", + gpio_nr); + return; + } + enable_irq_wake(OMAP_GPIO_IRQ(gpio_nr)); +} + +static int __init omap_serial_wakeup_init(void) +{ + if (!cpu_is_omap16xx()) + return 0; + + if (uart1_ck != NULL) + omap_serial_set_port_wakeup(37); + if (uart2_ck != NULL) + omap_serial_set_port_wakeup(18); + if (uart3_ck != NULL) + omap_serial_set_port_wakeup(49); + + return 0; +} +late_initcall(omap_serial_wakeup_init); + +#endif /* CONFIG_OMAP_SERIAL_WAKE */ + static int __init omap_init(void) { return platform_device_register(&serial_device); diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c index d540539c9bbb..191a9b1ee9b7 100644 --- a/arch/arm/mach-omap1/time.c +++ b/arch/arm/mach-omap1/time.c @@ -247,13 +247,6 @@ unsigned long long sched_clock(void) #define OMAP_32K_TIMER_TCR 0x04 #define OMAP_32K_TICKS_PER_HZ (32768 / HZ) -#if (32768 % HZ) != 0 -/* We cannot ignore modulo. - * Potential error can be as high as several percent. - */ -#define OMAP_32K_TICK_MODULO (32768 % HZ) -static unsigned modulo_count = 0; /* Counts 1/HZ units */ -#endif /* * TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1 @@ -296,13 +289,22 @@ static inline void omap_32k_timer_stop(void) } /* - * Rounds down to nearest usec + * Rounds down to nearest usec. Note that this will overflow for larger values. */ static inline unsigned long omap_32k_ticks_to_usecs(unsigned long ticks_32k) { return (ticks_32k * 5*5*5*5*5*5) >> 9; } +/* + * Rounds down to nearest nsec. + */ +static inline unsigned long long +omap_32k_ticks_to_nsecs(unsigned long ticks_32k) +{ + return (unsigned long long) ticks_32k * 1000 * 5*5*5*5*5*5 >> 9; +} + static unsigned long omap_32k_last_tick = 0; /* @@ -315,6 +317,15 @@ static unsigned long omap_32k_timer_gettimeoffset(void) } /* + * Returns current time from boot in nsecs. It's OK for this to wrap + * around for now, as it's just a relative time stamp. + */ +unsigned long long sched_clock(void) +{ + return omap_32k_ticks_to_nsecs(omap_32k_sync_timer_read()); +} + +/* * Timer interrupt for 32KHz timer. When dynamic tick is enabled, this * function is also called from other interrupts to remove latency * issues with dynamic tick. In the dynamic tick case, we need to lock @@ -330,19 +341,6 @@ static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id, now = omap_32k_sync_timer_read(); while (now - omap_32k_last_tick >= OMAP_32K_TICKS_PER_HZ) { -#ifdef OMAP_32K_TICK_MODULO - /* Modulo addition may put omap_32k_last_tick ahead of now - * and cause unwanted repetition of the while loop. - */ - if (unlikely(now - omap_32k_last_tick == ~0)) - break; - - modulo_count += OMAP_32K_TICK_MODULO; - if (modulo_count > HZ) { - ++omap_32k_last_tick; - modulo_count -= HZ; - } -#endif omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ; timer_tick(regs); } diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c index a10268618f74..e3587efec4bf 100644 --- a/arch/arm/mach-rpc/riscpc.c +++ b/arch/arm/mach-rpc/riscpc.c @@ -140,7 +140,7 @@ static struct plat_serial8250_port serial_platform_data[] = { static struct platform_device serial_device = { .name = "serial8250", - .id = 0, + .id = PLAT8250_DEV_PLATFORM, .dev = { .platform_data = serial_platform_data, }, diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c index e9182242da95..1a3367da6408 100644 --- a/arch/arm/mach-s3c2410/mach-bast.c +++ b/arch/arm/mach-s3c2410/mach-bast.c @@ -381,7 +381,7 @@ static struct plat_serial8250_port bast_sio_data[] = { static struct platform_device bast_sio = { .name = "serial8250", - .id = 0, + .id = PLAT8250_DEV_PLATFORM, .dev = { .platform_data = &bast_sio_data, }, diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c index 924e8464c212..8f9ab2893df4 100644 --- a/arch/arm/mach-s3c2410/mach-vr1000.c +++ b/arch/arm/mach-s3c2410/mach-vr1000.c @@ -221,7 +221,7 @@ static struct plat_serial8250_port serial_platform_data[] = { static struct platform_device serial_device = { .name = "serial8250", - .id = 0, + .id = PLAT8250_DEV_PLATFORM, .dev = { .platform_data = serial_platform_data, }, diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c index e737eae4521f..946c0d11c73b 100644 --- a/arch/arm/mach-shark/core.c +++ b/arch/arm/mach-shark/core.c @@ -41,7 +41,7 @@ static struct plat_serial8250_port serial_platform_data[] = { static struct platform_device serial_device = { .name = "serial8250", - .id = 0, + .id = PLAT8250_DEV_PLATFORM, .dev = { .platform_data = serial_platform_data, }, diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index 191788fb18d1..b0208c992576 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c @@ -16,6 +16,58 @@ #include <asm/tlbflush.h> #ifdef CONFIG_CPU_CACHE_VIPT + +void flush_cache_mm(struct mm_struct *mm) +{ + if (cache_is_vivt()) { + if (cpu_isset(smp_processor_id(), mm->cpu_vm_mask)) + __cpuc_flush_user_all(); + return; + } + + if (cache_is_vipt_aliasing()) { + asm( "mcr p15, 0, %0, c7, c14, 0\n" + " mcr p15, 0, %0, c7, c5, 0\n" + " mcr p15, 0, %0, c7, c10, 4" + : + : "r" (0) + : "cc"); + } +} + +void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) +{ + if (cache_is_vivt()) { + if (cpu_isset(smp_processor_id(), vma->vm_mm->cpu_vm_mask)) + __cpuc_flush_user_range(start & PAGE_MASK, PAGE_ALIGN(end), + vma->vm_flags); + return; + } + + if (cache_is_vipt_aliasing()) { + asm( "mcr p15, 0, %0, c7, c14, 0\n" + " mcr p15, 0, %0, c7, c5, 0\n" + " mcr p15, 0, %0, c7, c10, 4" + : + : "r" (0) + : "cc"); + } +} + +void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn) +{ + if (cache_is_vivt()) { + if (cpu_isset(smp_processor_id(), vma->vm_mm->cpu_vm_mask)) { + unsigned long addr = user_addr & PAGE_MASK; + __cpuc_flush_user_range(addr, addr + PAGE_SIZE, vma->vm_flags); + } + return; + } + + if (cache_is_vipt_aliasing()) + flush_pfn_alias(pfn, user_addr); +} + #define ALIAS_FLUSH_START 0xffff4000 #define TOP_PTE(x) pte_offset_kernel(top_pmd, x) diff --git a/arch/ppc/syslib/mpc10x_common.c b/arch/ppc/syslib/mpc10x_common.c index 87065e2e4c5f..3e039706bdbc 100644 --- a/arch/ppc/syslib/mpc10x_common.c +++ b/arch/ppc/syslib/mpc10x_common.c @@ -140,12 +140,12 @@ struct platform_device ppc_sys_platform_devices[] = { }, [MPC10X_UART0] = { .name = "serial8250", - .id = 0, + .id = PLAT8250_DEV_PLATFORM, .dev.platform_data = serial_plat_uart0, }, [MPC10X_UART1] = { .name = "serial8250", - .id = 1, + .id = PLAT8250_DEV_PLATFORM1, .dev.platform_data = serial_plat_uart1, }, diff --git a/arch/ppc/syslib/mpc83xx_devices.c b/arch/ppc/syslib/mpc83xx_devices.c index 5aaf0e58e1f9..95b3b8a7f0ba 100644 --- a/arch/ppc/syslib/mpc83xx_devices.c +++ b/arch/ppc/syslib/mpc83xx_devices.c @@ -165,7 +165,7 @@ struct platform_device ppc_sys_platform_devices[] = { }, [MPC83xx_DUART] = { .name = "serial8250", - .id = 0, + .id = PLAT8250_DEV_PLATFORM, .dev.platform_data = serial_platform_data, }, [MPC83xx_SEC2] = { diff --git a/arch/ppc/syslib/mpc85xx_devices.c b/arch/ppc/syslib/mpc85xx_devices.c index 8af322dd476a..bbc5ac0de878 100644 --- a/arch/ppc/syslib/mpc85xx_devices.c +++ b/arch/ppc/syslib/mpc85xx_devices.c @@ -282,7 +282,7 @@ struct platform_device ppc_sys_platform_devices[] = { }, [MPC85xx_DUART] = { .name = "serial8250", - .id = 0, + .id = PLAT8250_DEV_PLATFORM, .dev.platform_data = serial_platform_data, }, [MPC85xx_PERFMON] = { diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index d0bb68af0ea4..bfa8791c9807 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c @@ -1283,7 +1283,7 @@ void __init generic_find_legacy_serial_ports(u64 *physport, static struct platform_device serial_device = { .name = "serial8250", - .id = 0, + .id = PLAT8250_DEV_PLATFORM, .dev = { .platform_data = serial_ports, }, diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 6e9da1372225..8334496a7e0a 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -144,6 +144,22 @@ config I2C_I810 This driver can also be built as a module. If so, the module will be called i2c-i810. +config I2C_PXA + tristate "Intel PXA2XX I2C adapter (EXPERIMENTAL)" + depends on I2C && EXPERIMENTAL && ARCH_PXA + help + If you have devices in the PXA I2C bus, say yes to this option. + This driver can also be built as a module. If so, the module + will be called i2c-pxa. + +config I2C_PXA_SLAVE + bool "Intel PXA2XX I2C Slave comms support" + depends on I2C_PXA + help + Support I2C slave mode communications on the PXA I2C bus. This + is necessary for systems where the PXA may be a target on the + I2C bus. + config I2C_PIIX4 tristate "Intel PIIX4" depends on I2C && PCI diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 42d6d814da72..980b3e983670 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o +obj-$(CONFIG_I2C_PXA) += i2c-pxa.o obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c new file mode 100644 index 000000000000..fdf53ce04248 --- /dev/null +++ b/drivers/i2c/busses/i2c-pxa.c @@ -0,0 +1,1022 @@ +/* + * i2c_adap_pxa.c + * + * I2C adapter for the PXA I2C bus access. + * + * Copyright (C) 2002 Intrinsyc Software Inc. + * Copyright (C) 2004-2005 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * History: + * Apr 2002: Initial version [CS] + * Jun 2002: Properly seperated algo/adap [FB] + * Jan 2003: Fixed several bugs concerning interrupt handling [Kai-Uwe Bloem] + * Jan 2003: added limited signal handling [Kai-Uwe Bloem] + * Sep 2004: Major rework to ensure efficient bus handling [RMK] + * Dec 2004: Added support for PXA27x and slave device probing [Liam Girdwood] + * Feb 2005: Rework slave mode handling [RMK] + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/i2c-id.h> +#include <linux/init.h> +#include <linux/time.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/i2c-pxa.h> + +#include <asm/hardware.h> +#include <asm/irq.h> +#include <asm/arch/i2c.h> +#include <asm/arch/pxa-regs.h> + +struct pxa_i2c { + spinlock_t lock; + wait_queue_head_t wait; + struct i2c_msg *msg; + unsigned int msg_num; + unsigned int msg_idx; + unsigned int msg_ptr; + unsigned int slave_addr; + + struct i2c_adapter adap; +#ifdef CONFIG_I2C_PXA_SLAVE + struct i2c_slave_client *slave; +#endif + + unsigned int irqlogidx; + u32 isrlog[32]; + u32 icrlog[32]; +}; + +/* + * I2C Slave mode address + */ +#define I2C_PXA_SLAVE_ADDR 0x1 + +#ifdef DEBUG + +struct bits { + u32 mask; + const char *set; + const char *unset; +}; +#define BIT(m, s, u) { .mask = m, .set = s, .unset = u } + +static inline void +decode_bits(const char *prefix, const struct bits *bits, int num, u32 val) +{ + printk("%s %08x: ", prefix, val); + while (num--) { + const char *str = val & bits->mask ? bits->set : bits->unset; + if (str) + printk("%s ", str); + bits++; + } +} + +static const struct bits isr_bits[] = { + BIT(ISR_RWM, "RX", "TX"), + BIT(ISR_ACKNAK, "NAK", "ACK"), + BIT(ISR_UB, "Bsy", "Rdy"), + BIT(ISR_IBB, "BusBsy", "BusRdy"), + BIT(ISR_SSD, "SlaveStop", NULL), + BIT(ISR_ALD, "ALD", NULL), + BIT(ISR_ITE, "TxEmpty", NULL), + BIT(ISR_IRF, "RxFull", NULL), + BIT(ISR_GCAD, "GenCall", NULL), + BIT(ISR_SAD, "SlaveAddr", NULL), + BIT(ISR_BED, "BusErr", NULL), +}; + +static void decode_ISR(unsigned int val) +{ + decode_bits(KERN_DEBUG "ISR", isr_bits, ARRAY_SIZE(isr_bits), val); + printk("\n"); +} + +static const struct bits icr_bits[] = { + BIT(ICR_START, "START", NULL), + BIT(ICR_STOP, "STOP", NULL), + BIT(ICR_ACKNAK, "ACKNAK", NULL), + BIT(ICR_TB, "TB", NULL), + BIT(ICR_MA, "MA", NULL), + BIT(ICR_SCLE, "SCLE", "scle"), + BIT(ICR_IUE, "IUE", "iue"), + BIT(ICR_GCD, "GCD", NULL), + BIT(ICR_ITEIE, "ITEIE", NULL), + BIT(ICR_IRFIE, "IRFIE", NULL), + BIT(ICR_BEIE, "BEIE", NULL), + BIT(ICR_SSDIE, "SSDIE", NULL), + BIT(ICR_ALDIE, "ALDIE", NULL), + BIT(ICR_SADIE, "SADIE", NULL), + BIT(ICR_UR, "UR", "ur"), +}; + +static void decode_ICR(unsigned int val) +{ + decode_bits(KERN_DEBUG "ICR", icr_bits, ARRAY_SIZE(icr_bits), val); + printk("\n"); +} + +static unsigned int i2c_debug = DEBUG; + +static void i2c_pxa_show_state(struct pxa_i2c *i2c, int lno, const char *fname) +{ + dev_dbg(&i2c->adap.dev, "state:%s:%d: ISR=%08x, ICR=%08x, IBMR=%02x\n", fname, lno, ISR, ICR, IBMR); +} + +#define show_state(i2c) i2c_pxa_show_state(i2c, __LINE__, __FUNCTION__) +#else +#define i2c_debug 0 + +#define show_state(i2c) do { } while (0) +#define decode_ISR(val) do { } while (0) +#define decode_ICR(val) do { } while (0) +#endif + +#define eedbg(lvl, x...) do { if ((lvl) < 1) { printk(KERN_DEBUG "" x); } } while(0) + +static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret); + +static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why) +{ + unsigned int i; + printk("i2c: error: %s\n", why); + printk("i2c: msg_num: %d msg_idx: %d msg_ptr: %d\n", + i2c->msg_num, i2c->msg_idx, i2c->msg_ptr); + printk("i2c: ICR: %08x ISR: %08x\n" + "i2c: log: ", ICR, ISR); + for (i = 0; i < i2c->irqlogidx; i++) + printk("[%08x:%08x] ", i2c->isrlog[i], i2c->icrlog[i]); + printk("\n"); +} + +static inline int i2c_pxa_is_slavemode(struct pxa_i2c *i2c) +{ + return !(ICR & ICR_SCLE); +} + +static void i2c_pxa_abort(struct pxa_i2c *i2c) +{ + unsigned long timeout = jiffies + HZ/4; + + if (i2c_pxa_is_slavemode(i2c)) { + dev_dbg(&i2c->adap.dev, "%s: called in slave mode\n", __func__); + return; + } + + while (time_before(jiffies, timeout) && (IBMR & 0x1) == 0) { + unsigned long icr = ICR; + + icr &= ~ICR_START; + icr |= ICR_ACKNAK | ICR_STOP | ICR_TB; + + ICR = icr; + + show_state(i2c); + + msleep(1); + } + + ICR &= ~(ICR_MA | ICR_START | ICR_STOP); +} + +static int i2c_pxa_wait_bus_not_busy(struct pxa_i2c *i2c) +{ + int timeout = DEF_TIMEOUT; + + while (timeout-- && ISR & (ISR_IBB | ISR_UB)) { + if ((ISR & ISR_SAD) != 0) + timeout += 4; + + msleep(2); + show_state(i2c); + } + + if (timeout <= 0) + show_state(i2c); + + return timeout <= 0 ? I2C_RETRY : 0; +} + +static int i2c_pxa_wait_master(struct pxa_i2c *i2c) +{ + unsigned long timeout = jiffies + HZ*4; + + while (time_before(jiffies, timeout)) { + if (i2c_debug > 1) + dev_dbg(&i2c->adap.dev, "%s: %ld: ISR=%08x, ICR=%08x, IBMR=%02x\n", + __func__, (long)jiffies, ISR, ICR, IBMR); + + if (ISR & ISR_SAD) { + if (i2c_debug > 0) + dev_dbg(&i2c->adap.dev, "%s: Slave detected\n", __func__); + goto out; + } + + /* wait for unit and bus being not busy, and we also do a + * quick check of the i2c lines themselves to ensure they've + * gone high... + */ + if ((ISR & (ISR_UB | ISR_IBB)) == 0 && IBMR == 3) { + if (i2c_debug > 0) + dev_dbg(&i2c->adap.dev, "%s: done\n", __func__); + return 1; + } + + msleep(1); + } + + if (i2c_debug > 0) + dev_dbg(&i2c->adap.dev, "%s: did not free\n", __func__); + out: + return 0; +} + +static int i2c_pxa_set_master(struct pxa_i2c *i2c) +{ + if (i2c_debug) + dev_dbg(&i2c->adap.dev, "setting to bus master\n"); + + if ((ISR & (ISR_UB | ISR_IBB)) != 0) { + dev_dbg(&i2c->adap.dev, "%s: unit is busy\n", __func__); + if (!i2c_pxa_wait_master(i2c)) { + dev_dbg(&i2c->adap.dev, "%s: error: unit busy\n", __func__); + return I2C_RETRY; + } + } + + ICR |= ICR_SCLE; + return 0; +} + +#ifdef CONFIG_I2C_PXA_SLAVE +static int i2c_pxa_wait_slave(struct pxa_i2c *i2c) +{ + unsigned long timeout = jiffies + HZ*1; + + /* wait for stop */ + + show_state(i2c); + + while (time_before(jiffies, timeout)) { + if (i2c_debug > 1) + dev_dbg(&i2c->adap.dev, "%s: %ld: ISR=%08x, ICR=%08x, IBMR=%02x\n", + __func__, (long)jiffies, ISR, ICR, IBMR); + + if ((ISR & (ISR_UB|ISR_IBB|ISR_SAD)) == ISR_SAD || + (ICR & ICR_SCLE) == 0) { + if (i2c_debug > 1) + dev_dbg(&i2c->adap.dev, "%s: done\n", __func__); + return 1; + } + + msleep(1); + } + + if (i2c_debug > 0) + dev_dbg(&i2c->adap.dev, "%s: did not free\n", __func__); + return 0; +} + +/* + * clear the hold on the bus, and take of anything else + * that has been configured + */ +static void i2c_pxa_set_slave(struct pxa_i2c *i2c, int errcode) +{ + show_state(i2c); + + if (errcode < 0) { + udelay(100); /* simple delay */ + } else { + /* we need to wait for the stop condition to end */ + + /* if we where in stop, then clear... */ + if (ICR & ICR_STOP) { + udelay(100); + ICR &= ~ICR_STOP; + } + + if (!i2c_pxa_wait_slave(i2c)) { + dev_err(&i2c->adap.dev, "%s: wait timedout\n", + __func__); + return; + } + } + + ICR &= ~(ICR_STOP|ICR_ACKNAK|ICR_MA); + ICR &= ~ICR_SCLE; + + if (i2c_debug) { + dev_dbg(&i2c->adap.dev, "ICR now %08x, ISR %08x\n", ICR, ISR); + decode_ICR(ICR); + } +} +#else +#define i2c_pxa_set_slave(i2c, err) do { } while (0) +#endif + +static void i2c_pxa_reset(struct pxa_i2c *i2c) +{ + pr_debug("Resetting I2C Controller Unit\n"); + + /* abort any transfer currently under way */ + i2c_pxa_abort(i2c); + + /* reset according to 9.8 */ + ICR = ICR_UR; + ISR = I2C_ISR_INIT; + ICR &= ~ICR_UR; + + ISAR = i2c->slave_addr; + + /* set control register values */ + ICR = I2C_ICR_INIT; + +#ifdef CONFIG_I2C_PXA_SLAVE + dev_info(&i2c->adap.dev, "Enabling slave mode\n"); + ICR |= ICR_SADIE | ICR_ALDIE | ICR_SSDIE; +#endif + + i2c_pxa_set_slave(i2c, 0); + + /* enable unit */ + ICR |= ICR_IUE; + udelay(100); +} + + +#ifdef CONFIG_I2C_PXA_SLAVE +/* + * I2C EEPROM emulation. + */ +static struct i2c_eeprom_emu eeprom = { + .size = I2C_EEPROM_EMU_SIZE, + .watch = LIST_HEAD_INIT(eeprom.watch), +}; + +struct i2c_eeprom_emu *i2c_pxa_get_eeprom(void) +{ + return &eeprom; +} + +int i2c_eeprom_emu_addwatcher(struct i2c_eeprom_emu *emu, void *data, + unsigned int addr, unsigned int size, + struct i2c_eeprom_emu_watcher *watcher) +{ + struct i2c_eeprom_emu_watch *watch; + unsigned long flags; + + if (addr + size > emu->size) + return -EINVAL; + + watch = kmalloc(sizeof(struct i2c_eeprom_emu_watch), GFP_KERNEL); + if (watch) { + watch->start = addr; + watch->end = addr + size - 1; + watch->ops = watcher; + watch->data = data; + + local_irq_save(flags); + list_add(&watch->node, &emu->watch); + local_irq_restore(flags); + } + + return watch ? 0 : -ENOMEM; +} + +void i2c_eeprom_emu_delwatcher(struct i2c_eeprom_emu *emu, void *data, + struct i2c_eeprom_emu_watcher *watcher) +{ + struct i2c_eeprom_emu_watch *watch, *n; + unsigned long flags; + + list_for_each_entry_safe(watch, n, &emu->watch, node) { + if (watch->ops == watcher && watch->data == data) { + local_irq_save(flags); + list_del(&watch->node); + local_irq_restore(flags); + kfree(watch); + } + } +} + +static void i2c_eeprom_emu_event(void *ptr, i2c_slave_event_t event) +{ + struct i2c_eeprom_emu *emu = ptr; + + eedbg(3, "i2c_eeprom_emu_event: %d\n", event); + + switch (event) { + case I2C_SLAVE_EVENT_START_WRITE: + emu->seen_start = 1; + eedbg(2, "i2c_eeprom: write initiated\n"); + break; + + case I2C_SLAVE_EVENT_START_READ: + emu->seen_start = 0; + eedbg(2, "i2c_eeprom: read initiated\n"); + break; + + case I2C_SLAVE_EVENT_STOP: + emu->seen_start = 0; + eedbg(2, "i2c_eeprom: received stop\n"); + break; + + default: + eedbg(0, "i2c_eeprom: unhandled event\n"); + break; + } +} + +static int i2c_eeprom_emu_read(void *ptr) +{ + struct i2c_eeprom_emu *emu = ptr; + int ret; + + ret = emu->bytes[emu->ptr]; + emu->ptr = (emu->ptr + 1) % emu->size; + + return ret; +} + +static void i2c_eeprom_emu_write(void *ptr, unsigned int val) +{ + struct i2c_eeprom_emu *emu = ptr; + struct i2c_eeprom_emu_watch *watch; + + if (emu->seen_start != 0) { + eedbg(2, "i2c_eeprom_emu_write: setting ptr %02x\n", val); + emu->ptr = val; + emu->seen_start = 0; + return; + } + + emu->bytes[emu->ptr] = val; + + eedbg(1, "i2c_eeprom_emu_write: ptr=0x%02x, val=0x%02x\n", + emu->ptr, val); + + list_for_each_entry(watch, &emu->watch, node) { + if (!watch->ops || !watch->ops->write) + continue; + if (watch->start <= emu->ptr && watch->end >= emu->ptr) + watch->ops->write(watch->data, emu->ptr, val); + } + + emu->ptr = (emu->ptr + 1) % emu->size; +} + +struct i2c_slave_client eeprom_client = { + .data = &eeprom, + .event = i2c_eeprom_emu_event, + .read = i2c_eeprom_emu_read, + .write = i2c_eeprom_emu_write +}; + +/* + * PXA I2C Slave mode + */ + +static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr) +{ + if (isr & ISR_BED) { + /* what should we do here? */ + } else { + int ret = i2c->slave->read(i2c->slave->data); + + IDBR = ret; + ICR |= ICR_TB; /* allow next byte */ + } +} + +static void i2c_pxa_slave_rxfull(struct pxa_i2c *i2c, u32 isr) +{ + unsigned int byte = IDBR; + + if (i2c->slave != NULL) + i2c->slave->write(i2c->slave->data, byte); + + ICR |= ICR_TB; +} + +static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr) +{ + int timeout; + + if (i2c_debug > 0) + dev_dbg(&i2c->adap.dev, "SAD, mode is slave-%cx\n", + (isr & ISR_RWM) ? 'r' : 't'); + + if (i2c->slave != NULL) + i2c->slave->event(i2c->slave->data, + (isr & ISR_RWM) ? I2C_SLAVE_EVENT_START_READ : I2C_SLAVE_EVENT_START_WRITE); + + /* + * slave could interrupt in the middle of us generating a + * start condition... if this happens, we'd better back off + * and stop holding the poor thing up + */ + ICR &= ~(ICR_START|ICR_STOP); + ICR |= ICR_TB; + + timeout = 0x10000; + + while (1) { + if ((IBMR & 2) == 2) + break; + + timeout--; + + if (timeout <= 0) { + dev_err(&i2c->adap.dev, "timeout waiting for SCL high\n"); + break; + } + } + + ICR &= ~ICR_SCLE; +} + +static void i2c_pxa_slave_stop(struct pxa_i2c *i2c) +{ + if (i2c_debug > 2) + dev_dbg(&i2c->adap.dev, "ISR: SSD (Slave Stop)\n"); + + if (i2c->slave != NULL) + i2c->slave->event(i2c->slave->data, I2C_SLAVE_EVENT_STOP); + + if (i2c_debug > 2) + dev_dbg(&i2c->adap.dev, "ISR: SSD (Slave Stop) acked\n"); + + /* + * If we have a master-mode message waiting, + * kick it off now that the slave has completed. + */ + if (i2c->msg) + i2c_pxa_master_complete(i2c, I2C_RETRY); +} +#else +static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr) +{ + if (isr & ISR_BED) { + /* what should we do here? */ + } else { + IDBR = 0; + ICR |= ICR_TB; + } +} + +static void i2c_pxa_slave_rxfull(struct pxa_i2c *i2c, u32 isr) +{ + ICR |= ICR_TB | ICR_ACKNAK; +} + +static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr) +{ + int timeout; + + /* + * slave could interrupt in the middle of us generating a + * start condition... if this happens, we'd better back off + * and stop holding the poor thing up + */ + ICR &= ~(ICR_START|ICR_STOP); + ICR |= ICR_TB | ICR_ACKNAK; + + timeout = 0x10000; + + while (1) { + if ((IBMR & 2) == 2) + break; + + timeout--; + + if (timeout <= 0) { + dev_err(&i2c->adap.dev, "timeout waiting for SCL high\n"); + break; + } + } + + ICR &= ~ICR_SCLE; +} + +static void i2c_pxa_slave_stop(struct pxa_i2c *i2c) +{ + if (i2c->msg) + i2c_pxa_master_complete(i2c, I2C_RETRY); +} +#endif + +/* + * PXA I2C Master mode + */ + +static inline unsigned int i2c_pxa_addr_byte(struct i2c_msg *msg) +{ + unsigned int addr = (msg->addr & 0x7f) << 1; + + if (msg->flags & I2C_M_RD) + addr |= 1; + + return addr; +} + +static inline void i2c_pxa_start_message(struct pxa_i2c *i2c) +{ + u32 icr; + + /* + * Step 1: target slave address into IDBR + */ + IDBR = i2c_pxa_addr_byte(i2c->msg); + + /* + * Step 2: initiate the write. + */ + icr = ICR & ~(ICR_STOP | ICR_ALDIE); + ICR = icr | ICR_START | ICR_TB; +} + +/* + * We are protected by the adapter bus semaphore. + */ +static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num) +{ + long timeout; + int ret; + + /* + * Wait for the bus to become free. + */ + ret = i2c_pxa_wait_bus_not_busy(i2c); + if (ret) { + dev_err(&i2c->adap.dev, "i2c_pxa: timeout waiting for bus free\n"); + goto out; + } + + /* + * Set master mode. + */ + ret = i2c_pxa_set_master(i2c); + if (ret) { + dev_err(&i2c->adap.dev, "i2c_pxa_set_master: error %d\n", ret); + goto out; + } + + spin_lock_irq(&i2c->lock); + + i2c->msg = msg; + i2c->msg_num = num; + i2c->msg_idx = 0; + i2c->msg_ptr = 0; + i2c->irqlogidx = 0; + + i2c_pxa_start_message(i2c); + + spin_unlock_irq(&i2c->lock); + + /* + * The rest of the processing occurs in the interrupt handler. + */ + timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); + + /* + * We place the return code in i2c->msg_idx. + */ + ret = i2c->msg_idx; + + if (timeout == 0) + i2c_pxa_scream_blue_murder(i2c, "timeout"); + + out: + return ret; +} + +/* + * i2c_pxa_master_complete - complete the message and wake up. + */ +static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret) +{ + i2c->msg_ptr = 0; + i2c->msg = NULL; + i2c->msg_idx ++; + i2c->msg_num = 0; + if (ret) + i2c->msg_idx = ret; + wake_up(&i2c->wait); +} + +static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr) +{ + u32 icr = ICR & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB); + + again: + /* + * If ISR_ALD is set, we lost arbitration. + */ + if (isr & ISR_ALD) { + /* + * Do we need to do anything here? The PXA docs + * are vague about what happens. + */ + i2c_pxa_scream_blue_murder(i2c, "ALD set"); + + /* + * We ignore this error. We seem to see spurious ALDs + * for seemingly no reason. If we handle them as I think + * they should, we end up causing an I2C error, which + * is painful for some systems. + */ + return; /* ignore */ + } + + if (isr & ISR_BED) { + int ret = BUS_ERROR; + + /* + * I2C bus error - either the device NAK'd us, or + * something more serious happened. If we were NAK'd + * on the initial address phase, we can retry. + */ + if (isr & ISR_ACKNAK) { + if (i2c->msg_ptr == 0 && i2c->msg_idx == 0) + ret = I2C_RETRY; + else + ret = XFER_NAKED; + } + i2c_pxa_master_complete(i2c, ret); + } else if (isr & ISR_RWM) { + /* + * Read mode. We have just sent the address byte, and + * now we must initiate the transfer. + */ + if (i2c->msg_ptr == i2c->msg->len - 1 && + i2c->msg_idx == i2c->msg_num - 1) + icr |= ICR_STOP | ICR_ACKNAK; + + icr |= ICR_ALDIE | ICR_TB; + } else if (i2c->msg_ptr < i2c->msg->len) { + /* + * Write mode. Write the next data byte. + */ + IDBR = i2c->msg->buf[i2c->msg_ptr++]; + + icr |= ICR_ALDIE | ICR_TB; + + /* + * If this is the last byte of the last message, send + * a STOP. + */ + if (i2c->msg_ptr == i2c->msg->len && + i2c->msg_idx == i2c->msg_num - 1) + icr |= ICR_STOP; + } else if (i2c->msg_idx < i2c->msg_num - 1) { + /* + * Next segment of the message. + */ + i2c->msg_ptr = 0; + i2c->msg_idx ++; + i2c->msg++; + + /* + * If we aren't doing a repeated start and address, + * go back and try to send the next byte. Note that + * we do not support switching the R/W direction here. + */ + if (i2c->msg->flags & I2C_M_NOSTART) + goto again; + + /* + * Write the next address. + */ + IDBR = i2c_pxa_addr_byte(i2c->msg); + + /* + * And trigger a repeated start, and send the byte. + */ + icr &= ~ICR_ALDIE; + icr |= ICR_START | ICR_TB; + } else { + if (i2c->msg->len == 0) { + /* + * Device probes have a message length of zero + * and need the bus to be reset before it can + * be used again. + */ + i2c_pxa_reset(i2c); + } + i2c_pxa_master_complete(i2c, 0); + } + + i2c->icrlog[i2c->irqlogidx-1] = icr; + + ICR = icr; + show_state(i2c); +} + +static void i2c_pxa_irq_rxfull(struct pxa_i2c *i2c, u32 isr) +{ + u32 icr = ICR & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB); + + /* + * Read the byte. + */ + i2c->msg->buf[i2c->msg_ptr++] = IDBR; + + if (i2c->msg_ptr < i2c->msg->len) { + /* + * If this is the last byte of the last + * message, send a STOP. + */ + if (i2c->msg_ptr == i2c->msg->len - 1) + icr |= ICR_STOP | ICR_ACKNAK; + + icr |= ICR_ALDIE | ICR_TB; + } else { + i2c_pxa_master_complete(i2c, 0); + } + + i2c->icrlog[i2c->irqlogidx-1] = icr; + + ICR = icr; +} + +static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id, struct pt_regs *regs) +{ + struct pxa_i2c *i2c = dev_id; + u32 isr = ISR; + + if (i2c_debug > 2 && 0) { + dev_dbg(&i2c->adap.dev, "%s: ISR=%08x, ICR=%08x, IBMR=%02x\n", + __func__, isr, ICR, IBMR); + decode_ISR(isr); + } + + if (i2c->irqlogidx < sizeof(i2c->isrlog)/sizeof(u32)) + i2c->isrlog[i2c->irqlogidx++] = isr; + + show_state(i2c); + + /* + * Always clear all pending IRQs. + */ + ISR = isr & (ISR_SSD|ISR_ALD|ISR_ITE|ISR_IRF|ISR_SAD|ISR_BED); + + if (isr & ISR_SAD) + i2c_pxa_slave_start(i2c, isr); + if (isr & ISR_SSD) + i2c_pxa_slave_stop(i2c); + + if (i2c_pxa_is_slavemode(i2c)) { + if (isr & ISR_ITE) + i2c_pxa_slave_txempty(i2c, isr); + if (isr & ISR_IRF) + i2c_pxa_slave_rxfull(i2c, isr); + } else if (i2c->msg) { + if (isr & ISR_ITE) + i2c_pxa_irq_txempty(i2c, isr); + if (isr & ISR_IRF) + i2c_pxa_irq_rxfull(i2c, isr); + } else { + i2c_pxa_scream_blue_murder(i2c, "spurious irq"); + } + + return IRQ_HANDLED; +} + + +static int i2c_pxa_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + struct pxa_i2c *i2c = adap->algo_data; + int ret, i; + + for (i = adap->retries; i >= 0; i--) { + ret = i2c_pxa_do_xfer(i2c, msgs, num); + if (ret != I2C_RETRY) + goto out; + + if (i2c_debug) + dev_dbg(&adap->dev, "Retrying transmission\n"); + udelay(100); + } + i2c_pxa_scream_blue_murder(i2c, "exhausted retries"); + ret = -EREMOTEIO; + out: + i2c_pxa_set_slave(i2c, ret); + return ret; +} + +static struct i2c_algorithm i2c_pxa_algorithm = { + .name = "PXA-I2C-Algorithm", + .id = I2C_ALGO_PXA, + .master_xfer = i2c_pxa_xfer, +}; + +static struct pxa_i2c i2c_pxa = { + .lock = SPIN_LOCK_UNLOCKED, + .wait = __WAIT_QUEUE_HEAD_INITIALIZER(i2c_pxa.wait), + .adap = { + .name = "pxa2xx-i2c", + .id = I2C_ALGO_PXA, + .algo = &i2c_pxa_algorithm, + .retries = 5, + }, +}; + +static int i2c_pxa_probe(struct device *dev) +{ + struct pxa_i2c *i2c = &i2c_pxa; + struct i2c_pxa_platform_data *plat = dev->platform_data; + int ret; + +#ifdef CONFIG_PXA27x + pxa_gpio_mode(GPIO117_I2CSCL_MD); + pxa_gpio_mode(GPIO118_I2CSDA_MD); + udelay(100); +#endif + + i2c->slave_addr = I2C_PXA_SLAVE_ADDR; + +#ifdef CONFIG_I2C_PXA_SLAVE + i2c->slave = &eeprom_client; + if (plat) { + i2c->slave_addr = plat->slave_addr; + if (plat->slave) + i2c->slave = plat->slave; + } +#endif + + pxa_set_cken(CKEN14_I2C, 1); + ret = request_irq(IRQ_I2C, i2c_pxa_handler, SA_INTERRUPT, + "pxa2xx-i2c", i2c); + if (ret) + goto out; + + i2c_pxa_reset(i2c); + + i2c->adap.algo_data = i2c; + i2c->adap.dev.parent = dev; + + ret = i2c_add_adapter(&i2c->adap); + if (ret < 0) { + printk(KERN_INFO "I2C: Failed to add bus\n"); + goto err_irq; + } + + dev_set_drvdata(dev, i2c); + +#ifdef CONFIG_I2C_PXA_SLAVE + printk(KERN_INFO "I2C: %s: PXA I2C adapter, slave address %d\n", + i2c->adap.dev.bus_id, i2c->slave_addr); +#else + printk(KERN_INFO "I2C: %s: PXA I2C adapter\n", + i2c->adap.dev.bus_id); +#endif + return 0; + + err_irq: + free_irq(IRQ_I2C, i2c); + out: + return ret; +} + +static int i2c_pxa_remove(struct device *dev) +{ + struct pxa_i2c *i2c = dev_get_drvdata(dev); + + dev_set_drvdata(dev, NULL); + + i2c_del_adapter(&i2c->adap); + free_irq(IRQ_I2C, i2c); + pxa_set_cken(CKEN14_I2C, 0); + + return 0; +} + +static struct device_driver i2c_pxa_driver = { + .name = "pxa2xx-i2c", + .bus = &platform_bus_type, + .probe = i2c_pxa_probe, + .remove = i2c_pxa_remove, +}; + +static int __init i2c_adap_pxa_init(void) +{ + return driver_register(&i2c_pxa_driver); +} + +static void i2c_adap_pxa_exit(void) +{ + return driver_unregister(&i2c_pxa_driver); +} + +module_init(i2c_adap_pxa_init); +module_exit(i2c_adap_pxa_exit); diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 0a117c61cd18..ceae379a4d4c 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1079,13 +1079,17 @@ static void mmc_setup(struct mmc_host *host) /** * mmc_detect_change - process change of state on a MMC socket * @host: host which changed state. + * @delay: optional delay to wait before detection (jiffies) * * All we know is that card(s) have been inserted or removed * from the socket(s). We don't know which socket or cards. */ -void mmc_detect_change(struct mmc_host *host) +void mmc_detect_change(struct mmc_host *host, unsigned long delay) { - schedule_work(&host->detect); + if (delay) + schedule_delayed_work(&host->detect, delay); + else + schedule_work(&host->detect); } EXPORT_SYMBOL(mmc_detect_change); @@ -1189,7 +1193,7 @@ int mmc_add_host(struct mmc_host *host) ret = mmc_add_host_sysfs(host); if (ret == 0) { mmc_power_off(host); - mmc_detect_change(host); + mmc_detect_change(host, 0); } return ret; @@ -1259,7 +1263,7 @@ EXPORT_SYMBOL(mmc_suspend_host); */ int mmc_resume_host(struct mmc_host *host) { - mmc_detect_change(host); + mmc_detect_change(host, 0); return 0; } diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index 716c4ef4faf6..91c74843dc0d 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -442,7 +442,7 @@ static void mmci_check_status(unsigned long data) status = host->plat->status(mmc_dev(host->mmc)); if (status ^ host->oldstat) - mmc_detect_change(host->mmc); + mmc_detect_change(host->mmc, 0); host->oldstat = status; mod_timer(&host->timer, jiffies + HZ); diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c index e99a53b09e32..b53af57074e3 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/pxamci.c @@ -423,7 +423,9 @@ static void pxamci_dma_irq(int dma, void *devid, struct pt_regs *regs) static irqreturn_t pxamci_detect_irq(int irq, void *devid, struct pt_regs *regs) { - mmc_detect_change(devid); + struct pxamci_host *host = mmc_priv(devid); + + mmc_detect_change(devid, host->pdata->detect_delay); return IRQ_HANDLED; } diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index dec01d38c782..a62c86fef5cc 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -1122,7 +1122,7 @@ static void wbsd_detect_card(unsigned long data) DBG("Executing card detection\n"); - mmc_detect_change(host->mmc); + mmc_detect_change(host->mmc, 0); } /* @@ -1198,7 +1198,7 @@ static void wbsd_tasklet_card(unsigned long param) */ spin_unlock(&host->lock); - mmc_detect_change(host->mmc); + mmc_detect_change(host->mmc, 0); } else spin_unlock(&host->lock); diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 55a72c7ad001..83598e32179c 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -14,8 +14,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.2.20" -#define DRV_MODULE_RELDATE "August 22, 2005" +#define DRV_MODULE_VERSION "1.2.21" +#define DRV_MODULE_RELDATE "September 7, 2005" #define RUN_AT(x) (jiffies + (x)) @@ -1533,6 +1533,7 @@ bnx2_msi(int irq, void *dev_instance, struct pt_regs *regs) struct net_device *dev = dev_instance; struct bnx2 *bp = dev->priv; + prefetch(bp->status_blk); REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM | BNX2_PCICFG_INT_ACK_CMD_MASK_INT); @@ -1558,7 +1559,7 @@ bnx2_interrupt(int irq, void *dev_instance, struct pt_regs *regs) * When using MSI, the MSI message will always complete after * the status block write. */ - if ((bp->status_blk->status_idx == bp->last_status_idx) || + if ((bp->status_blk->status_idx == bp->last_status_idx) && (REG_RD(bp, BNX2_PCICFG_MISC_STATUS) & BNX2_PCICFG_MISC_STATUS_INTA_VALUE)) return IRQ_NONE; diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 9ad3f5740cd8..62857b6a6ee4 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -50,6 +50,7 @@ #endif #include <linux/workqueue.h> #include <linux/crc32.h> +#include <linux/prefetch.h> /* Hardware data structures and register definitions automatically * generated from RTL code. Do not modify. diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 30a0a3d10145..5b65e208893b 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -2536,7 +2536,7 @@ static int __init serial8250_init(void) goto out; serial8250_isa_devs = platform_device_register_simple("serial8250", - -1, NULL, 0); + PLAT8250_DEV_LEGACY, NULL, 0); if (IS_ERR(serial8250_isa_devs)) { ret = PTR_ERR(serial8250_isa_devs); goto unreg; diff --git a/drivers/serial/8250_accent.c b/drivers/serial/8250_accent.c index 1f2c276063ef..9c10262f2469 100644 --- a/drivers/serial/8250_accent.c +++ b/drivers/serial/8250_accent.c @@ -29,7 +29,7 @@ static struct plat_serial8250_port accent_data[] = { static struct platform_device accent_device = { .name = "serial8250", - .id = 2, + .id = PLAT8250_DEV_ACCENT, .dev = { .platform_data = accent_data, }, diff --git a/drivers/serial/8250_boca.c b/drivers/serial/8250_boca.c index 465c9ea1e7a3..3bfe0f7b26fb 100644 --- a/drivers/serial/8250_boca.c +++ b/drivers/serial/8250_boca.c @@ -43,7 +43,7 @@ static struct plat_serial8250_port boca_data[] = { static struct platform_device boca_device = { .name = "serial8250", - .id = 3, + .id = PLAT8250_DEV_BOCA, .dev = { .platform_data = boca_data, }, diff --git a/drivers/serial/8250_fourport.c b/drivers/serial/8250_fourport.c index e9b4d908ef42..6375d68b7913 100644 --- a/drivers/serial/8250_fourport.c +++ b/drivers/serial/8250_fourport.c @@ -35,7 +35,7 @@ static struct plat_serial8250_port fourport_data[] = { static struct platform_device fourport_device = { .name = "serial8250", - .id = 1, + .id = PLAT8250_DEV_FOURPORT, .dev = { .platform_data = fourport_data, }, diff --git a/drivers/serial/8250_hub6.c b/drivers/serial/8250_hub6.c index 77f396f84b4c..daf569cd3c8f 100644 --- a/drivers/serial/8250_hub6.c +++ b/drivers/serial/8250_hub6.c @@ -40,7 +40,7 @@ static struct plat_serial8250_port hub6_data[] = { static struct platform_device hub6_device = { .name = "serial8250", - .id = 4, + .id = PLAT8250_DEV_HUB6, .dev = { .platform_data = hub6_data, }, diff --git a/drivers/serial/8250_mca.c b/drivers/serial/8250_mca.c index f0c40d68b8c1..ac205256d5f3 100644 --- a/drivers/serial/8250_mca.c +++ b/drivers/serial/8250_mca.c @@ -44,7 +44,7 @@ static struct plat_serial8250_port mca_data[] = { static struct platform_device mca_device = { .name = "serial8250", - .id = 5, + .id = PLAT8250_DEV_MCA, .dev = { .platform_data = mca_data, }, diff --git a/include/asm-arm/arch-pxa/hardware.h b/include/asm-arm/arch-pxa/hardware.h index 72b04d846a23..cf35721cfa45 100644 --- a/include/asm-arm/arch-pxa/hardware.h +++ b/include/asm-arm/arch-pxa/hardware.h @@ -44,24 +44,12 @@ #ifndef __ASSEMBLY__ -#if 0 -# define __REG(x) (*((volatile u32 *)io_p2v(x))) -#else -/* - * This __REG() version gives the same results as the one above, except - * that we are fooling gcc somehow so it generates far better and smaller - * assembly code for access to contigous registers. It's a shame that gcc - * doesn't guess this by itself. - */ -#include <asm/types.h> -typedef struct { volatile u32 offset[4096]; } __regbase; -# define __REGP(x) ((__regbase *)((x)&~4095))->offset[((x)&4095)>>2] -# define __REG(x) __REGP(io_p2v(x)) -#endif +# define __REG(x) (*((volatile unsigned long *)io_p2v(x))) /* With indexed regs we don't want to feed the index through io_p2v() especially if it is a variable, otherwise horrible code will result. */ -# define __REG2(x,y) (*(volatile u32 *)((u32)&__REG(x) + (y))) +# define __REG2(x,y) \ + (*(volatile unsigned long *)((unsigned long)&__REG(x) + (y))) # define __PREG(x) (io_v2p((u32)&(x))) diff --git a/include/asm-arm/arch-pxa/i2c.h b/include/asm-arm/arch-pxa/i2c.h new file mode 100644 index 000000000000..46ec2243974a --- /dev/null +++ b/include/asm-arm/arch-pxa/i2c.h @@ -0,0 +1,70 @@ +/* + * i2c_pxa.h + * + * Copyright (C) 2002 Intrinsyc Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#ifndef _I2C_PXA_H_ +#define _I2C_PXA_H_ + +#if 0 +#define DEF_TIMEOUT 3 +#else +/* need a longer timeout if we're dealing with the fact we may well be + * looking at a multi-master environment +*/ +#define DEF_TIMEOUT 32 +#endif + +#define BUS_ERROR (-EREMOTEIO) +#define XFER_NAKED (-ECONNREFUSED) +#define I2C_RETRY (-2000) /* an error has occurred retry transmit */ + +/* ICR initialize bit values +* +* 15. FM 0 (100 Khz operation) +* 14. UR 0 (No unit reset) +* 13. SADIE 0 (Disables the unit from interrupting on slave addresses +* matching its slave address) +* 12. ALDIE 0 (Disables the unit from interrupt when it loses arbitration +* in master mode) +* 11. SSDIE 0 (Disables interrupts from a slave stop detected, in slave mode) +* 10. BEIE 1 (Enable interrupts from detected bus errors, no ACK sent) +* 9. IRFIE 1 (Enable interrupts from full buffer received) +* 8. ITEIE 1 (Enables the I2C unit to interrupt when transmit buffer empty) +* 7. GCD 1 (Disables i2c unit response to general call messages as a slave) +* 6. IUE 0 (Disable unit until we change settings) +* 5. SCLE 1 (Enables the i2c clock output for master mode (drives SCL) +* 4. MA 0 (Only send stop with the ICR stop bit) +* 3. TB 0 (We are not transmitting a byte initially) +* 2. ACKNAK 0 (Send an ACK after the unit receives a byte) +* 1. STOP 0 (Do not send a STOP) +* 0. START 0 (Do not send a START) +* +*/ +#define I2C_ICR_INIT (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE) + +/* I2C status register init values + * + * 10. BED 1 (Clear bus error detected) + * 9. SAD 1 (Clear slave address detected) + * 7. IRF 1 (Clear IDBR Receive Full) + * 6. ITE 1 (Clear IDBR Transmit Empty) + * 5. ALD 1 (Clear Arbitration Loss Detected) + * 4. SSD 1 (Clear Slave Stop Detected) + */ +#define I2C_ISR_INIT 0x7FF /* status register init */ + +struct i2c_slave_client; + +struct i2c_pxa_platform_data { + unsigned int slave_addr; + struct i2c_slave_client *slave; +}; + +extern void pxa_set_i2c_info(struct i2c_pxa_platform_data *info); +#endif diff --git a/include/asm-arm/arch-pxa/mmc.h b/include/asm-arm/arch-pxa/mmc.h index 9718063a2119..88c17dd02ed2 100644 --- a/include/asm-arm/arch-pxa/mmc.h +++ b/include/asm-arm/arch-pxa/mmc.h @@ -9,6 +9,7 @@ struct mmc_host; struct pxamci_platform_data { unsigned int ocr_mask; /* available voltages */ + unsigned long detect_delay; /* delay in jiffies before detecting cards after interrupt */ int (*init)(struct device *, irqreturn_t (*)(int, void *, struct pt_regs *), void *); int (*get_ro)(struct device *); void (*setpower)(struct device *, unsigned int); diff --git a/include/asm-arm/arch-sa1100/hardware.h b/include/asm-arm/arch-sa1100/hardware.h index 10c62db34362..19c3b1e186bb 100644 --- a/include/asm-arm/arch-sa1100/hardware.h +++ b/include/asm-arm/arch-sa1100/hardware.h @@ -49,23 +49,9 @@ ( (((x)&0x00ffffff) | (((x)&(0x30000000>>VIO_SHIFT))<<VIO_SHIFT)) + PIO_START ) #ifndef __ASSEMBLY__ -#include <asm/types.h> -#if 0 -# define __REG(x) (*((volatile u32 *)io_p2v(x))) -#else -/* - * This __REG() version gives the same results as the one above, except - * that we are fooling gcc somehow so it generates far better and smaller - * assembly code for access to contigous registers. It's a shame that gcc - * doesn't guess this by itself. - */ -typedef struct { volatile u32 offset[4096]; } __regbase; -# define __REGP(x) ((__regbase *)((x)&~4095))->offset[((x)&4095)>>2] -# define __REG(x) __REGP(io_p2v(x)) -#endif - -# define __PREG(x) (io_v2p((u32)&(x))) +# define __REG(x) (*((volatile unsigned long *)io_p2v(x))) +# define __PREG(x) (io_v2p((unsigned long)&(x))) #else diff --git a/include/asm-arm/cacheflush.h b/include/asm-arm/cacheflush.h index 035cdcff43d2..e81baff4f54b 100644 --- a/include/asm-arm/cacheflush.h +++ b/include/asm-arm/cacheflush.h @@ -256,7 +256,7 @@ extern void dmac_flush_range(unsigned long, unsigned long); * Convert calls to our calling convention. */ #define flush_cache_all() __cpuc_flush_kern_all() - +#ifndef CONFIG_CPU_CACHE_VIPT static inline void flush_cache_mm(struct mm_struct *mm) { if (cpu_isset(smp_processor_id(), mm->cpu_vm_mask)) @@ -279,6 +279,11 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned l __cpuc_flush_user_range(addr, addr + PAGE_SIZE, vma->vm_flags); } } +#else +extern void flush_cache_mm(struct mm_struct *mm); +extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); +extern void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn); +#endif /* * flush_cache_user_range is used when we want to ensure that the diff --git a/include/linux/i2c-pxa.h b/include/linux/i2c-pxa.h new file mode 100644 index 000000000000..5f3eaf802223 --- /dev/null +++ b/include/linux/i2c-pxa.h @@ -0,0 +1,48 @@ +#ifndef _LINUX_I2C_ALGO_PXA_H +#define _LINUX_I2C_ALGO_PXA_H + +struct i2c_eeprom_emu_watcher { + void (*write)(void *, unsigned int addr, unsigned char newval); +}; + +struct i2c_eeprom_emu_watch { + struct list_head node; + unsigned int start; + unsigned int end; + struct i2c_eeprom_emu_watcher *ops; + void *data; +}; + +#define I2C_EEPROM_EMU_SIZE (256) + +struct i2c_eeprom_emu { + unsigned int size; + unsigned int ptr; + unsigned int seen_start; + struct list_head watch; + + unsigned char bytes[I2C_EEPROM_EMU_SIZE]; +}; + +typedef enum i2c_slave_event_e { + I2C_SLAVE_EVENT_START_READ, + I2C_SLAVE_EVENT_START_WRITE, + I2C_SLAVE_EVENT_STOP +} i2c_slave_event_t; + +struct i2c_slave_client { + void *data; + void (*event)(void *ptr, i2c_slave_event_t event); + int (*read) (void *ptr); + void (*write)(void *ptr, unsigned int val); +}; + +extern int i2c_eeprom_emu_addwatcher(struct i2c_eeprom_emu *, void *data, + unsigned int addr, unsigned int size, + struct i2c_eeprom_emu_watcher *); + +extern void i2c_eeprom_emu_delwatcher(struct i2c_eeprom_emu *, void *data, struct i2c_eeprom_emu_watcher *watcher); + +extern struct i2c_eeprom_emu *i2c_pxa_get_eeprom(void); + +#endif /* _LINUX_I2C_ALGO_PXA_H */ diff --git a/include/linux/in6.h b/include/linux/in6.h index dcf5720ffcbb..bd32b79d6295 100644 --- a/include/linux/in6.h +++ b/include/linux/in6.h @@ -148,13 +148,13 @@ struct in6_flowlabel_req */ #define IPV6_ADDRFORM 1 -#define IPV6_PKTINFO 2 -#define IPV6_HOPOPTS 3 -#define IPV6_DSTOPTS 4 -#define IPV6_RTHDR 5 -#define IPV6_PKTOPTIONS 6 +#define IPV6_2292PKTINFO 2 +#define IPV6_2292HOPOPTS 3 +#define IPV6_2292DSTOPTS 4 +#define IPV6_2292RTHDR 5 +#define IPV6_2292PKTOPTIONS 6 #define IPV6_CHECKSUM 7 -#define IPV6_HOPLIMIT 8 +#define IPV6_2292HOPLIMIT 8 #define IPV6_NEXTHOP 9 #define IPV6_AUTHHDR 10 /* obsolete */ #define IPV6_FLOWINFO 11 @@ -198,4 +198,28 @@ struct in6_flowlabel_req * MCAST_MSFILTER 48 */ +/* RFC3542 advanced socket options (50-67) */ +#define IPV6_RECVPKTINFO 50 +#define IPV6_PKTINFO 51 +#if 0 +#define IPV6_RECVPATHMTU 52 +#define IPV6_PATHMTU 53 +#define IPV6_DONTFRAG 54 +#define IPV6_USE_MIN_MTU 55 +#endif +#define IPV6_RECVHOPOPTS 56 +#define IPV6_HOPOPTS 57 +#if 0 +#define IPV6_RECVRTHDRDSTOPTS 58 /* Unused, see net/ipv6/datagram.c */ +#endif +#define IPV6_RTHDRDSTOPTS 59 +#define IPV6_RECVRTHDR 60 +#define IPV6_RTHDR 61 +#define IPV6_RECVDSTOPTS 62 +#define IPV6_DSTOPTS 63 +#define IPV6_RECVHOPLIMIT 64 +#define IPV6_HOPLIMIT 65 +#define IPV6_RECVTCLASS 66 +#define IPV6_TCLASS 67 + #endif diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 3c7dbc6a0a70..6c5f7b39a4b0 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -189,6 +189,7 @@ struct inet6_skb_parm { __u16 dst0; __u16 srcrt; __u16 dst1; + __u16 lastopt; }; #define IP6CB(skb) ((struct inet6_skb_parm*)((skb)->cb)) @@ -234,14 +235,20 @@ struct ipv6_pinfo { /* pktoption flags */ union { struct { - __u8 srcrt:2, + __u16 srcrt:2, + osrcrt:2, rxinfo:1, + rxoinfo:1, rxhlim:1, + rxohlim:1, hopopts:1, + ohopopts:1, dstopts:1, - rxflow:1; + odstopts:1, + rxflow:1, + rxtclass:1; } bits; - __u8 all; + __u16 all; } rxopt; /* sockopt flags */ @@ -250,6 +257,7 @@ struct ipv6_pinfo { sndflow:1, pmtudisc:2, ipv6only:1; + __u8 tclass; __u32 dst_cookie; @@ -263,6 +271,7 @@ struct ipv6_pinfo { struct ipv6_txoptions *opt; struct rt6_info *rt; int hop_limit; + int tclass; } cork; }; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 6014160d9c06..c1f021eddffa 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -109,6 +109,8 @@ struct mmc_host { struct mmc_card *card_selected; /* the selected MMC card */ struct work_struct detect; + + unsigned long private[0] ____cacheline_aligned; }; extern struct mmc_host *mmc_alloc_host(int extra, struct device *); @@ -116,14 +118,18 @@ extern int mmc_add_host(struct mmc_host *); extern void mmc_remove_host(struct mmc_host *); extern void mmc_free_host(struct mmc_host *); -#define mmc_priv(x) ((void *)((x) + 1)) +static inline void *mmc_priv(struct mmc_host *host) +{ + return (void *)host->private; +} + #define mmc_dev(x) ((x)->dev) #define mmc_hostname(x) ((x)->class_dev.class_id) extern int mmc_suspend_host(struct mmc_host *, pm_message_t); extern int mmc_resume_host(struct mmc_host *); -extern void mmc_detect_change(struct mmc_host *); +extern void mmc_detect_change(struct mmc_host *, unsigned long delay); extern void mmc_request_done(struct mmc_host *, struct mmc_request *); #endif diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index d8a023d804d4..317a979b24de 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -30,6 +30,21 @@ struct plat_serial8250_port { }; /* + * Allocate 8250 platform device IDs. Nothing is implied by + * the numbering here, except for the legacy entry being -1. + */ +enum { + PLAT8250_DEV_LEGACY = -1, + PLAT8250_DEV_PLATFORM, + PLAT8250_DEV_PLATFORM1, + PLAT8250_DEV_FOURPORT, + PLAT8250_DEV_ACCENT, + PLAT8250_DEV_BOCA, + PLAT8250_DEV_HUB6, + PLAT8250_DEV_MCA, +}; + +/* * This should be used by drivers which want to register * their own 8250 ports without registering their own * platform device. Using these will make your driver diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 9b12fe731612..27db8da43aa4 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -401,6 +401,9 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch, #endif return 0; } +#ifndef SUPPORT_SYSRQ +#define uart_handle_sysrq_char(port,ch,regs) uart_handle_sysrq_char(port, 0, NULL) +#endif /* * We do the SysRQ and SAK checking like this... diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index da7da9c0ed1b..2741c0c55e83 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1167,7 +1167,7 @@ static inline void skb_postpull_rcsum(struct sk_buff *skb, static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len) { - if (len >= skb->len) + if (likely(len >= skb->len)) return 0; if (skb->ip_summed == CHECKSUM_HW) skb->ip_summed = CHECKSUM_NONE; diff --git a/include/net/ax25.h b/include/net/ax25.h index 364b046e9f47..227d3378decd 100644 --- a/include/net/ax25.h +++ b/include/net/ax25.h @@ -258,7 +258,7 @@ extern struct sock *ax25_make_new(struct sock *, struct ax25_dev *); /* ax25_addr.c */ extern ax25_address null_ax25_address; extern char *ax2asc(char *buf, ax25_address *); -extern ax25_address *asc2ax(char *); +extern void asc2ax(ax25_address *addr, char *callsign); extern int ax25cmp(ax25_address *, ax25_address *); extern int ax25digicmp(ax25_digi *, ax25_digi *); extern unsigned char *ax25_addr_parse(unsigned char *, int, ax25_address *, ax25_address *, ax25_digi *, int *, int *); diff --git a/include/net/compat.h b/include/net/compat.h index 482eb820f13a..290bab46d457 100644 --- a/include/net/compat.h +++ b/include/net/compat.h @@ -33,7 +33,8 @@ extern asmlinkage long compat_sys_sendmsg(int,struct compat_msghdr __user *,unsi extern asmlinkage long compat_sys_recvmsg(int,struct compat_msghdr __user *,unsigned); extern asmlinkage long compat_sys_getsockopt(int, int, int, char __user *, int __user *); extern int put_cmsg_compat(struct msghdr*, int, int, int, void *); -extern int cmsghdr_from_user_compat_to_kern(struct msghdr *, struct sock *, unsigned char *, - int); + +struct sock; +extern int cmsghdr_from_user_compat_to_kern(struct msghdr *, struct sock *, unsigned char *, int); #endif /* NET_COMPAT_H */ diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 3203eaff4bd4..65ec86678a08 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -233,6 +233,10 @@ extern int ip6_ra_control(struct sock *sk, int sel, extern int ipv6_parse_hopopts(struct sk_buff *skb, int); extern struct ipv6_txoptions * ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt); +extern struct ipv6_txoptions * ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt, + int newtype, + struct ipv6_opt_hdr __user *newopt, + int newoptlen); extern int ip6_frag_nqueues; extern atomic_t ip6_frag_mem; @@ -373,6 +377,7 @@ extern int ip6_append_data(struct sock *sk, int length, int transhdrlen, int hlimit, + int tclass, struct ipv6_txoptions *opt, struct flowi *fl, struct rt6_info *rt, diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h index 8b075ab7a26c..4e86f2de6638 100644 --- a/include/net/transp_v6.h +++ b/include/net/transp_v6.h @@ -37,7 +37,7 @@ extern int datagram_recv_ctl(struct sock *sk, extern int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, struct ipv6_txoptions *opt, - int *hlimit); + int *hlimit, int *tclass); #define LOOPBACK4_IPV6 __constant_htonl(0x7f000006) diff --git a/net/ax25/ax25_addr.c b/net/ax25/ax25_addr.c index dca179daf415..0164a155b8c4 100644 --- a/net/ax25/ax25_addr.c +++ b/net/ax25/ax25_addr.c @@ -67,37 +67,34 @@ char *ax2asc(char *buf, ax25_address *a) /* * ascii -> ax25 conversion */ -ax25_address *asc2ax(char *callsign) +void asc2ax(ax25_address *addr, char *callsign) { - static ax25_address addr; char *s; int n; for (s = callsign, n = 0; n < 6; n++) { if (*s != '\0' && *s != '-') - addr.ax25_call[n] = *s++; + addr->ax25_call[n] = *s++; else - addr.ax25_call[n] = ' '; - addr.ax25_call[n] <<= 1; - addr.ax25_call[n] &= 0xFE; + addr->ax25_call[n] = ' '; + addr->ax25_call[n] <<= 1; + addr->ax25_call[n] &= 0xFE; } if (*s++ == '\0') { - addr.ax25_call[6] = 0x00; - return &addr; + addr->ax25_call[6] = 0x00; + return; } - addr.ax25_call[6] = *s++ - '0'; + addr->ax25_call[6] = *s++ - '0'; if (*s != '\0') { - addr.ax25_call[6] *= 10; - addr.ax25_call[6] += *s++ - '0'; + addr->ax25_call[6] *= 10; + addr->ax25_call[6] += *s++ - '0'; } - addr.ax25_call[6] <<= 1; - addr.ax25_call[6] &= 0x1E; - - return &addr; + addr->ax25_call[6] <<= 1; + addr->ax25_call[6] &= 0x1E; } /* diff --git a/net/ieee80211/Kconfig b/net/ieee80211/Kconfig index 58ed4319e693..91b16fbf91f0 100644 --- a/net/ieee80211/Kconfig +++ b/net/ieee80211/Kconfig @@ -1,6 +1,5 @@ config IEEE80211 tristate "Generic IEEE 802.11 Networking Stack" - select NET_RADIO ---help--- This option enables the hardware independent IEEE 802.11 networking stack. diff --git a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c index 2b5cf9c51309..bb7246683b74 100644 --- a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c +++ b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c @@ -104,12 +104,28 @@ out: static struct ip_conntrack_helper helper = { .name = "netbios-ns", .tuple = { - .src.u.udp.port = __constant_htons(137), - .dst.protonum = IPPROTO_UDP, + .src = { + .u = { + .udp = { + .port = __constant_htons(137), + } + } + }, + .dst = { + .protonum = IPPROTO_UDP, + }, }, .mask = { - .src.u.udp.port = 0xFFFF, - .dst.protonum = 0xFF, + .src = { + .u = { + .udp = { + .port = 0xFFFF, + } + } + }, + .dst = { + .protonum = 0xFF, + }, }, .max_expected = 1, .me = THIS_MODULE, diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index f115a84a4ac6..f057025a719e 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -92,10 +92,7 @@ static inline struct rtable *route_reverse(struct sk_buff *skb, fl.fl_ip_sport = tcph->dest; fl.fl_ip_dport = tcph->source; - if (xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0)) { - dst_release(&rt->u.dst); - rt = NULL; - } + xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0); return rt; } diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 8c0b14e3beec..8549f26e2495 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1760,6 +1760,7 @@ static inline int __mkroute_input(struct sk_buff *skb, goto cleanup; } + atomic_set(&rth->u.dst.__refcnt, 1); rth->u.dst.flags= DST_HOST; #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED if (res->fi->fib_nhs > 1) @@ -1820,7 +1821,6 @@ static inline int ip_mkroute_input_def(struct sk_buff *skb, err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos, &rth); if (err) return err; - atomic_set(&rth->u.dst.__refcnt, 1); /* put it into the cache */ hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5), tos); @@ -1834,8 +1834,8 @@ static inline int ip_mkroute_input(struct sk_buff *skb, u32 daddr, u32 saddr, u32 tos) { #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED - struct rtable* rth = NULL; - unsigned char hop, hopcount, lasthop; + struct rtable* rth = NULL, *rtres; + unsigned char hop, hopcount; int err = -EINVAL; unsigned int hash; @@ -1844,8 +1844,6 @@ static inline int ip_mkroute_input(struct sk_buff *skb, else hopcount = 1; - lasthop = hopcount - 1; - /* distinguish between multipath and singlepath */ if (hopcount < 2) return ip_mkroute_input_def(skb, res, fl, in_dev, daddr, @@ -1855,6 +1853,10 @@ static inline int ip_mkroute_input(struct sk_buff *skb, for (hop = 0; hop < hopcount; hop++) { res->nh_sel = hop; + /* put reference to previous result */ + if (hop) + ip_rt_put(rtres); + /* create a routing cache entry */ err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos, &rth); @@ -1863,7 +1865,7 @@ static inline int ip_mkroute_input(struct sk_buff *skb, /* put it into the cache */ hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5), tos); - err = rt_intern_hash(hash, rth, (struct rtable**)&skb->dst); + err = rt_intern_hash(hash, rth, &rtres); if (err) return err; @@ -1873,13 +1875,8 @@ static inline int ip_mkroute_input(struct sk_buff *skb, FIB_RES_NETMASK(*res), res->prefixlen, &FIB_RES_NH(*res)); - - /* only for the last hop the reference count is handled - * outside - */ - if (hop == lasthop) - atomic_set(&(skb->dst->__refcnt), 1); } + skb->dst = &rtres->u.dst; return err; #else /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */ return ip_mkroute_input_def(skb, res, fl, in_dev, daddr, saddr, tos); @@ -2208,6 +2205,7 @@ static inline int __mkroute_output(struct rtable **result, goto cleanup; } + atomic_set(&rth->u.dst.__refcnt, 1); rth->u.dst.flags= DST_HOST; #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED if (res->fi) { @@ -2290,8 +2288,6 @@ static inline int ip_mkroute_output_def(struct rtable **rp, if (err == 0) { u32 tos = RT_FL_TOS(oldflp); - atomic_set(&rth->u.dst.__refcnt, 1); - hash = rt_hash_code(oldflp->fl4_dst, oldflp->fl4_src ^ (oldflp->oif << 5), tos); err = rt_intern_hash(hash, rth, rp); @@ -2326,6 +2322,10 @@ static inline int ip_mkroute_output(struct rtable** rp, dev2nexthop = FIB_RES_DEV(*res); dev_hold(dev2nexthop); + /* put reference to previous result */ + if (hop) + ip_rt_put(*rp); + err = __mkroute_output(&rth, res, fl, oldflp, dev2nexthop, flags); @@ -2350,7 +2350,6 @@ static inline int ip_mkroute_output(struct rtable** rp, if (err != 0) return err; } - atomic_set(&(*rp)->u.dst.__refcnt, 1); return err; } else { return ip_mkroute_output_def(rp, res, fl, oldflp, dev_out, diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 6094db5e11be..15e1134da1b2 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -499,7 +499,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss /* If this packet has been sent out already, we must * adjust the various packet counters. */ - if (after(tp->snd_nxt, TCP_SKB_CB(buff)->end_seq)) { + if (!before(tp->snd_nxt, TCP_SKB_CB(buff)->end_seq)) { int diff = old_factor - tcp_skb_pcount(skb) - tcp_skb_pcount(buff); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index e5beca7de86c..e0bd1013cb0d 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1141,7 +1141,7 @@ int udp_rcv(struct sk_buff *skb) if (ulen > len || ulen < sizeof(*uh)) goto short_packet; - if (pskb_trim(skb, ulen)) + if (pskb_trim_rcsum(skb, ulen)) goto short_packet; if (udp_checksum_init(skb, uh, ulen, saddr, daddr) < 0) diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 01468fab3d3d..cc518405b3e1 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -175,10 +175,8 @@ ipv4_connected: if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) { - dst_release(dst); + if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) goto out; - } /* source address lookup done in ip6_dst_lookup */ @@ -390,32 +388,101 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) put_cmsg(msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim); } + if (np->rxopt.bits.rxtclass) { + int tclass = (ntohl(*(u32 *)skb->nh.ipv6h) >> 20) & 0xff; + put_cmsg(msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass); + } + if (np->rxopt.bits.rxflow && (*(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK)) { u32 flowinfo = *(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK; put_cmsg(msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo); } + + /* HbH is allowed only once */ if (np->rxopt.bits.hopopts && opt->hop) { u8 *ptr = skb->nh.raw + opt->hop; put_cmsg(msg, SOL_IPV6, IPV6_HOPOPTS, (ptr[1]+1)<<3, ptr); } - if (np->rxopt.bits.dstopts && opt->dst0) { + + if (opt->lastopt && + (np->rxopt.bits.dstopts || np->rxopt.bits.srcrt)) { + /* + * Silly enough, but we need to reparse in order to + * report extension headers (except for HbH) + * in order. + * + * Also note that IPV6_RECVRTHDRDSTOPTS is NOT + * (and WILL NOT be) defined because + * IPV6_RECVDSTOPTS is more generic. --yoshfuji + */ + unsigned int off = sizeof(struct ipv6hdr); + u8 nexthdr = skb->nh.ipv6h->nexthdr; + + while (off <= opt->lastopt) { + unsigned len; + u8 *ptr = skb->nh.raw + off; + + switch(nexthdr) { + case IPPROTO_DSTOPTS: + nexthdr = ptr[0]; + len = (ptr[1] + 1) << 3; + if (np->rxopt.bits.dstopts) + put_cmsg(msg, SOL_IPV6, IPV6_DSTOPTS, len, ptr); + break; + case IPPROTO_ROUTING: + nexthdr = ptr[0]; + len = (ptr[1] + 1) << 3; + if (np->rxopt.bits.srcrt) + put_cmsg(msg, SOL_IPV6, IPV6_RTHDR, len, ptr); + break; + case IPPROTO_AH: + nexthdr = ptr[0]; + len = (ptr[1] + 1) << 2; + break; + default: + nexthdr = ptr[0]; + len = (ptr[1] + 1) << 3; + break; + } + + off += len; + } + } + + /* socket options in old style */ + if (np->rxopt.bits.rxoinfo) { + struct in6_pktinfo src_info; + + src_info.ipi6_ifindex = opt->iif; + ipv6_addr_copy(&src_info.ipi6_addr, &skb->nh.ipv6h->daddr); + put_cmsg(msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info); + } + if (np->rxopt.bits.rxohlim) { + int hlim = skb->nh.ipv6h->hop_limit; + put_cmsg(msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim); + } + if (np->rxopt.bits.ohopopts && opt->hop) { + u8 *ptr = skb->nh.raw + opt->hop; + put_cmsg(msg, SOL_IPV6, IPV6_2292HOPOPTS, (ptr[1]+1)<<3, ptr); + } + if (np->rxopt.bits.odstopts && opt->dst0) { u8 *ptr = skb->nh.raw + opt->dst0; - put_cmsg(msg, SOL_IPV6, IPV6_DSTOPTS, (ptr[1]+1)<<3, ptr); + put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, (ptr[1]+1)<<3, ptr); } - if (np->rxopt.bits.srcrt && opt->srcrt) { + if (np->rxopt.bits.osrcrt && opt->srcrt) { struct ipv6_rt_hdr *rthdr = (struct ipv6_rt_hdr *)(skb->nh.raw + opt->srcrt); - put_cmsg(msg, SOL_IPV6, IPV6_RTHDR, (rthdr->hdrlen+1) << 3, rthdr); + put_cmsg(msg, SOL_IPV6, IPV6_2292RTHDR, (rthdr->hdrlen+1) << 3, rthdr); } - if (np->rxopt.bits.dstopts && opt->dst1) { + if (np->rxopt.bits.odstopts && opt->dst1) { u8 *ptr = skb->nh.raw + opt->dst1; - put_cmsg(msg, SOL_IPV6, IPV6_DSTOPTS, (ptr[1]+1)<<3, ptr); + put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, (ptr[1]+1)<<3, ptr); } return 0; } int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, struct ipv6_txoptions *opt, - int *hlimit) + int *hlimit, int *tclass) { struct in6_pktinfo *src_info; struct cmsghdr *cmsg; @@ -438,6 +505,7 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, switch (cmsg->cmsg_type) { case IPV6_PKTINFO: + case IPV6_2292PKTINFO: if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct in6_pktinfo))) { err = -EINVAL; goto exit_f; @@ -492,6 +560,7 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, fl->fl6_flowlabel = IPV6_FLOWINFO_MASK & *(u32 *)CMSG_DATA(cmsg); break; + case IPV6_2292HOPOPTS: case IPV6_HOPOPTS: if (opt->hopopt || cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) { err = -EINVAL; @@ -512,7 +581,7 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, opt->hopopt = hdr; break; - case IPV6_DSTOPTS: + case IPV6_2292DSTOPTS: if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) { err = -EINVAL; goto exit_f; @@ -536,6 +605,33 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, opt->dst1opt = hdr; break; + case IPV6_DSTOPTS: + case IPV6_RTHDRDSTOPTS: + if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) { + err = -EINVAL; + goto exit_f; + } + + hdr = (struct ipv6_opt_hdr *)CMSG_DATA(cmsg); + len = ((hdr->hdrlen + 1) << 3); + if (cmsg->cmsg_len < CMSG_LEN(len)) { + err = -EINVAL; + goto exit_f; + } + if (!capable(CAP_NET_RAW)) { + err = -EPERM; + goto exit_f; + } + if (cmsg->cmsg_type == IPV6_DSTOPTS) { + opt->opt_flen += len; + opt->dst1opt = hdr; + } else { + opt->opt_nflen += len; + opt->dst0opt = hdr; + } + break; + + case IPV6_2292RTHDR: case IPV6_RTHDR: if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_rt_hdr))) { err = -EINVAL; @@ -568,7 +664,7 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, opt->opt_nflen += len; opt->srcrt = rthdr; - if (opt->dst1opt) { + if (cmsg->cmsg_type == IPV6_2292RTHDR && opt->dst1opt) { int dsthdrlen = ((opt->dst1opt->hdrlen+1)<<3); opt->opt_nflen += dsthdrlen; @@ -579,6 +675,7 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, break; + case IPV6_2292HOPLIMIT: case IPV6_HOPLIMIT: if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) { err = -EINVAL; @@ -588,6 +685,24 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, *hlimit = *(int *)CMSG_DATA(cmsg); break; + case IPV6_TCLASS: + { + int tc; + + err = -EINVAL; + if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) { + goto exit_f; + } + + tc = *(int *)CMSG_DATA(cmsg); + if (tc < 0 || tc > 0xff) + goto exit_f; + + err = 0; + *tclass = tc; + + break; + } default: LIMIT_NETDEBUG(KERN_DEBUG "invalid cmsg type: %d\n", cmsg->cmsg_type); diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 5be6da2584ee..47122728212a 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -164,6 +164,7 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp, unsigned int *nhoffp) return -1; } + opt->lastopt = skb->h.raw - skb->nh.raw; opt->dst1 = skb->h.raw - skb->nh.raw; if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) { @@ -243,6 +244,7 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp, unsigned int *nhoffp) looped_back: if (hdr->segments_left == 0) { + opt->lastopt = skb->h.raw - skb->nh.raw; opt->srcrt = skb->h.raw - skb->nh.raw; skb->h.raw += (hdr->hdrlen + 1) << 3; opt->dst0 = opt->dst1; @@ -459,11 +461,10 @@ static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff) IP6_INC_STATS_BH(IPSTATS_MIB_INTRUNCATEDPKTS); goto drop; } - if (pkt_len + sizeof(struct ipv6hdr) < skb->len) { - __pskb_trim(skb, pkt_len + sizeof(struct ipv6hdr)); - if (skb->ip_summed == CHECKSUM_HW) - skb->ip_summed = CHECKSUM_NONE; - } + + if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) + goto drop; + return 1; drop: @@ -539,10 +540,15 @@ void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto, struct in6_addr **daddr) { - if (opt->srcrt) + if (opt->srcrt) { ipv6_push_rthdr(skb, proto, opt->srcrt, daddr); - if (opt->dst0opt) - ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt); + /* + * IPV6_RTHDRDSTOPTS is ignored + * unless IPV6_RTHDR is set (RFC3542). + */ + if (opt->dst0opt) + ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt); + } if (opt->hopopt) ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt); } @@ -573,3 +579,97 @@ ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt) } return opt2; } + +static int ipv6_renew_option(void *ohdr, + struct ipv6_opt_hdr __user *newopt, int newoptlen, + int inherit, + struct ipv6_opt_hdr **hdr, + char **p) +{ + if (inherit) { + if (ohdr) { + memcpy(*p, ohdr, ipv6_optlen((struct ipv6_opt_hdr *)ohdr)); + *hdr = (struct ipv6_opt_hdr *)*p; + *p += CMSG_ALIGN(ipv6_optlen(*(struct ipv6_opt_hdr **)hdr)); + } + } else { + if (newopt) { + if (copy_from_user(*p, newopt, newoptlen)) + return -EFAULT; + *hdr = (struct ipv6_opt_hdr *)*p; + if (ipv6_optlen(*(struct ipv6_opt_hdr **)hdr) > newoptlen) + return -EINVAL; + *p += CMSG_ALIGN(newoptlen); + } + } + return 0; +} + +struct ipv6_txoptions * +ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt, + int newtype, + struct ipv6_opt_hdr __user *newopt, int newoptlen) +{ + int tot_len = 0; + char *p; + struct ipv6_txoptions *opt2; + int err; + + if (newtype != IPV6_HOPOPTS && opt->hopopt) + tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt)); + if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt) + tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt)); + if (newtype != IPV6_RTHDR && opt->srcrt) + tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt)); + if (newtype != IPV6_DSTOPTS && opt->dst1opt) + tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt)); + if (newopt && newoptlen) + tot_len += CMSG_ALIGN(newoptlen); + + if (!tot_len) + return NULL; + + opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC); + if (!opt2) + return ERR_PTR(-ENOBUFS); + + memset(opt2, 0, tot_len); + + opt2->tot_len = tot_len; + p = (char *)(opt2 + 1); + + err = ipv6_renew_option(opt->hopopt, newopt, newoptlen, + newtype != IPV6_HOPOPTS, + &opt2->hopopt, &p); + if (err) + goto out; + + err = ipv6_renew_option(opt->dst0opt, newopt, newoptlen, + newtype != IPV6_RTHDRDSTOPTS, + &opt2->dst0opt, &p); + if (err) + goto out; + + err = ipv6_renew_option(opt->srcrt, newopt, newoptlen, + newtype != IPV6_RTHDR, + (struct ipv6_opt_hdr **)opt2->srcrt, &p); + if (err) + goto out; + + err = ipv6_renew_option(opt->dst1opt, newopt, newoptlen, + newtype != IPV6_DSTOPTS, + &opt2->dst1opt, &p); + if (err) + goto out; + + opt2->opt_nflen = (opt2->hopopt ? ipv6_optlen(opt2->hopopt) : 0) + + (opt2->dst0opt ? ipv6_optlen(opt2->dst0opt) : 0) + + (opt2->srcrt ? ipv6_optlen(opt2->srcrt) : 0); + opt2->opt_flen = (opt2->dst1opt ? ipv6_optlen(opt2->dst1opt) : 0); + + return opt2; +out: + sock_kfree_s(sk, p, tot_len); + return ERR_PTR(err); +} + diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index fa8f1bb0aa52..b7185fb3377c 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -287,7 +287,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, int iif = 0; int addr_type = 0; int len; - int hlimit; + int hlimit, tclass; int err = 0; if ((u8*)hdr < skb->head || (u8*)(hdr+1) > skb->tail) @@ -374,7 +374,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, if (err) goto out; if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) - goto out_dst_release; + goto out; if (ipv6_addr_is_multicast(&fl.fl6_dst)) hlimit = np->mcast_hops; @@ -385,6 +385,10 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, if (hlimit < 0) hlimit = ipv6_get_hoplimit(dst->dev); + tclass = np->cork.tclass; + if (tclass < 0) + tclass = 0; + msg.skb = skb; msg.offset = skb->nh.raw - skb->data; @@ -400,7 +404,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, err = ip6_append_data(sk, icmpv6_getfrag, &msg, len + sizeof(struct icmp6hdr), sizeof(struct icmp6hdr), - hlimit, NULL, &fl, (struct rt6_info*)dst, + hlimit, tclass, NULL, &fl, (struct rt6_info*)dst, MSG_DONTWAIT); if (err) { ip6_flush_pending_frames(sk); @@ -434,6 +438,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) struct dst_entry *dst; int err = 0; int hlimit; + int tclass; saddr = &skb->nh.ipv6h->daddr; @@ -464,7 +469,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) if (err) goto out; if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) - goto out_dst_release; + goto out; if (ipv6_addr_is_multicast(&fl.fl6_dst)) hlimit = np->mcast_hops; @@ -475,13 +480,17 @@ static void icmpv6_echo_reply(struct sk_buff *skb) if (hlimit < 0) hlimit = ipv6_get_hoplimit(dst->dev); + tclass = np->cork.tclass; + if (tclass < 0) + tclass = 0; + idev = in6_dev_get(skb->dev); msg.skb = skb; msg.offset = 0; err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr), - sizeof(struct icmp6hdr), hlimit, NULL, &fl, + sizeof(struct icmp6hdr), hlimit, tclass, NULL, &fl, (struct rt6_info*)dst, MSG_DONTWAIT); if (err) { @@ -496,7 +505,6 @@ static void icmpv6_echo_reply(struct sk_buff *skb) out_put: if (likely(idev != NULL)) in6_dev_put(idev); -out_dst_release: dst_release(dst); out: icmpv6_xmit_unlock(); diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index b6c73da5ff35..a7db762de14a 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -225,16 +225,20 @@ struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions * opt_space, struct ip6_flowlabel * fl, struct ipv6_txoptions * fopt) { - struct ipv6_txoptions * fl_opt = fl->opt; + struct ipv6_txoptions * fl_opt = fl ? fl->opt : NULL; - if (fopt == NULL || fopt->opt_flen == 0) - return fl_opt; + if (fopt == NULL || fopt->opt_flen == 0) { + if (!fl_opt || !fl_opt->dst0opt || fl_opt->srcrt) + return fl_opt; + } if (fl_opt != NULL) { opt_space->hopopt = fl_opt->hopopt; - opt_space->dst0opt = fl_opt->dst0opt; + opt_space->dst0opt = fl_opt->srcrt ? fl_opt->dst0opt : NULL; opt_space->srcrt = fl_opt->srcrt; opt_space->opt_nflen = fl_opt->opt_nflen; + if (fl_opt->dst0opt && !fl_opt->srcrt) + opt_space->opt_nflen -= ipv6_optlen(fl_opt->dst0opt); } else { if (fopt->opt_nflen == 0) return fopt; @@ -310,7 +314,7 @@ fl_create(struct in6_flowlabel_req *freq, char __user *optval, int optlen, int * msg.msg_control = (void*)(fl->opt+1); flowi.oif = 0; - err = datagram_send_ctl(&msg, &flowi, fl->opt, &junk); + err = datagram_send_ctl(&msg, &flowi, fl->opt, &junk, &junk); if (err) goto done; err = -EINVAL; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 01ef94f7c7f1..2f589f24c093 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -166,7 +166,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, struct ipv6hdr *hdr; u8 proto = fl->proto; int seg_len = skb->len; - int hlimit; + int hlimit, tclass; u32 mtu; if (opt) { @@ -202,7 +202,6 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, * Fill in the IPv6 header */ - *(u32*)hdr = htonl(0x60000000) | fl->fl6_flowlabel; hlimit = -1; if (np) hlimit = np->hop_limit; @@ -211,6 +210,14 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, if (hlimit < 0) hlimit = ipv6_get_hoplimit(dst->dev); + tclass = -1; + if (np) + tclass = np->tclass; + if (tclass < 0) + tclass = 0; + + *(u32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl->fl6_flowlabel; + hdr->payload_len = htons(seg_len); hdr->nexthdr = proto; hdr->hop_limit = hlimit; @@ -762,10 +769,11 @@ out_err_release: return err; } -int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), - void *from, int length, int transhdrlen, - int hlimit, struct ipv6_txoptions *opt, struct flowi *fl, struct rt6_info *rt, - unsigned int flags) +int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, + int offset, int len, int odd, struct sk_buff *skb), + void *from, int length, int transhdrlen, + int hlimit, int tclass, struct ipv6_txoptions *opt, struct flowi *fl, + struct rt6_info *rt, unsigned int flags) { struct inet_sock *inet = inet_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk); @@ -803,6 +811,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offse np->cork.rt = rt; inet->cork.fl = *fl; np->cork.hop_limit = hlimit; + np->cork.tclass = tclass; inet->cork.fragsize = mtu = dst_mtu(rt->u.dst.path); if (dst_allfrag(rt->u.dst.path)) inet->cork.flags |= IPCORK_ALLFRAG; @@ -1084,7 +1093,8 @@ int ip6_push_pending_frames(struct sock *sk) skb->nh.ipv6h = hdr = (struct ipv6hdr*) skb_push(skb, sizeof(struct ipv6hdr)); - *(u32*)hdr = fl->fl6_flowlabel | htonl(0x60000000); + *(u32*)hdr = fl->fl6_flowlabel | + htonl(0x60000000 | ((int)np->cork.tclass << 20)); if (skb->len <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 09613729404c..cf94372d1af3 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -673,11 +673,12 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) if ((dst = ip6_tnl_dst_check(t)) != NULL) dst_hold(dst); - else + else { dst = ip6_route_output(NULL, &fl); - if (dst->error || xfrm_lookup(&dst, &fl, NULL, 0) < 0) - goto tx_err_link_failure; + if (dst->error || xfrm_lookup(&dst, &fl, NULL, 0) < 0) + goto tx_err_link_failure; + } tdev = dst->dev; diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 76466af8331e..8567873d0dd8 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -210,39 +210,139 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, retv = 0; break; - case IPV6_PKTINFO: + case IPV6_RECVPKTINFO: np->rxopt.bits.rxinfo = valbool; retv = 0; break; + + case IPV6_2292PKTINFO: + np->rxopt.bits.rxoinfo = valbool; + retv = 0; + break; - case IPV6_HOPLIMIT: + case IPV6_RECVHOPLIMIT: np->rxopt.bits.rxhlim = valbool; retv = 0; break; - case IPV6_RTHDR: + case IPV6_2292HOPLIMIT: + np->rxopt.bits.rxohlim = valbool; + retv = 0; + break; + + case IPV6_RECVRTHDR: if (val < 0 || val > 2) goto e_inval; np->rxopt.bits.srcrt = val; retv = 0; break; - case IPV6_HOPOPTS: + case IPV6_2292RTHDR: + if (val < 0 || val > 2) + goto e_inval; + np->rxopt.bits.osrcrt = val; + retv = 0; + break; + + case IPV6_RECVHOPOPTS: np->rxopt.bits.hopopts = valbool; retv = 0; break; - case IPV6_DSTOPTS: + case IPV6_2292HOPOPTS: + np->rxopt.bits.ohopopts = valbool; + retv = 0; + break; + + case IPV6_RECVDSTOPTS: np->rxopt.bits.dstopts = valbool; retv = 0; break; + case IPV6_2292DSTOPTS: + np->rxopt.bits.odstopts = valbool; + retv = 0; + break; + + case IPV6_TCLASS: + if (val < 0 || val > 0xff) + goto e_inval; + np->tclass = val; + retv = 0; + break; + + case IPV6_RECVTCLASS: + np->rxopt.bits.rxtclass = valbool; + retv = 0; + break; + case IPV6_FLOWINFO: np->rxopt.bits.rxflow = valbool; retv = 0; break; - case IPV6_PKTOPTIONS: + case IPV6_HOPOPTS: + case IPV6_RTHDRDSTOPTS: + case IPV6_RTHDR: + case IPV6_DSTOPTS: + { + struct ipv6_txoptions *opt; + if (optlen == 0) + optval = 0; + + /* hop-by-hop / destination options are privileged option */ + retv = -EPERM; + if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW)) + break; + + retv = -EINVAL; + if (optlen & 0x7 || optlen > 8 * 255) + break; + + opt = ipv6_renew_options(sk, np->opt, optname, + (struct ipv6_opt_hdr __user *)optval, + optlen); + if (IS_ERR(opt)) { + retv = PTR_ERR(opt); + break; + } + + /* routing header option needs extra check */ + if (optname == IPV6_RTHDR && opt->srcrt) { + struct ipv6_rt_hdr *rthdr = opt->srcrt; + if (rthdr->type) + goto sticky_done; + if ((rthdr->hdrlen & 1) || + (rthdr->hdrlen >> 1) != rthdr->segments_left) + goto sticky_done; + } + + retv = 0; + if (sk->sk_type == SOCK_STREAM) { + if (opt) { + struct tcp_sock *tp = tcp_sk(sk); + if (!((1 << sk->sk_state) & + (TCPF_LISTEN | TCPF_CLOSE)) + && inet_sk(sk)->daddr != LOOPBACK4_IPV6) { + tp->ext_header_len = opt->opt_flen + opt->opt_nflen; + tcp_sync_mss(sk, tp->pmtu_cookie); + } + } + opt = xchg(&np->opt, opt); + sk_dst_reset(sk); + } else { + write_lock(&sk->sk_dst_lock); + opt = xchg(&np->opt, opt); + write_unlock(&sk->sk_dst_lock); + sk_dst_reset(sk); + } +sticky_done: + if (opt) + sock_kfree_s(sk, opt, opt->tot_len); + break; + } + + case IPV6_2292PKTOPTIONS: { struct ipv6_txoptions *opt = NULL; struct msghdr msg; @@ -276,7 +376,7 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, msg.msg_controllen = optlen; msg.msg_control = (void*)(opt+1); - retv = datagram_send_ctl(&msg, &fl, opt, &junk); + retv = datagram_send_ctl(&msg, &fl, opt, &junk, &junk); if (retv) goto done; update: @@ -529,6 +629,17 @@ e_inval: return -EINVAL; } +int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr, + char __user *optval, int len) +{ + if (!hdr) + return 0; + len = min_t(int, len, ipv6_optlen(hdr)); + if (copy_to_user(optval, hdr, ipv6_optlen(hdr))) + return -EFAULT; + return len; +} + int ipv6_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { @@ -567,7 +678,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, return err; } - case IPV6_PKTOPTIONS: + case IPV6_2292PKTOPTIONS: { struct msghdr msg; struct sk_buff *skb; @@ -601,6 +712,16 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, int hlim = np->mcast_hops; put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim); } + if (np->rxopt.bits.rxoinfo) { + struct in6_pktinfo src_info; + src_info.ipi6_ifindex = np->mcast_oif; + ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr); + put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info); + } + if (np->rxopt.bits.rxohlim) { + int hlim = np->mcast_hops; + put_cmsg(&msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim); + } } len -= msg.msg_controllen; return put_user(len, optlen); @@ -625,26 +746,67 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, val = np->ipv6only; break; - case IPV6_PKTINFO: + case IPV6_RECVPKTINFO: val = np->rxopt.bits.rxinfo; break; - case IPV6_HOPLIMIT: + case IPV6_2292PKTINFO: + val = np->rxopt.bits.rxoinfo; + break; + + case IPV6_RECVHOPLIMIT: val = np->rxopt.bits.rxhlim; break; - case IPV6_RTHDR: + case IPV6_2292HOPLIMIT: + val = np->rxopt.bits.rxohlim; + break; + + case IPV6_RECVRTHDR: val = np->rxopt.bits.srcrt; break; + case IPV6_2292RTHDR: + val = np->rxopt.bits.osrcrt; + break; + case IPV6_HOPOPTS: + case IPV6_RTHDRDSTOPTS: + case IPV6_RTHDR: + case IPV6_DSTOPTS: + { + + lock_sock(sk); + len = ipv6_getsockopt_sticky(sk, np->opt->hopopt, + optval, len); + release_sock(sk); + return put_user(len, optlen); + } + + case IPV6_RECVHOPOPTS: val = np->rxopt.bits.hopopts; break; - case IPV6_DSTOPTS: + case IPV6_2292HOPOPTS: + val = np->rxopt.bits.ohopopts; + break; + + case IPV6_RECVDSTOPTS: val = np->rxopt.bits.dstopts; break; + case IPV6_2292DSTOPTS: + val = np->rxopt.bits.odstopts; + break; + + case IPV6_TCLASS: + val = np->tclass; + break; + + case IPV6_RECVTCLASS: + val = np->rxopt.bits.rxtclass; + break; + case IPV6_FLOWINFO: val = np->rxopt.bits.rxflow; break; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index a7eae30f4554..555a31347eda 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -447,10 +447,8 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, return; err = xfrm_lookup(&dst, &fl, NULL, 0); - if (err < 0) { - dst_release(dst); + if (err < 0) return; - } if (inc_opt) { if (dev->addr_len) @@ -539,10 +537,8 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, return; err = xfrm_lookup(&dst, &fl, NULL, 0); - if (err < 0) { - dst_release(dst); + if (err < 0) return; - } len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr); send_llinfo = dev->addr_len && !ipv6_addr_any(saddr); @@ -616,10 +612,8 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, return; err = xfrm_lookup(&dst, &fl, NULL, 0); - if (err < 0) { - dst_release(dst); + if (err < 0) return; - } len = sizeof(struct icmp6hdr); if (dev->addr_len) @@ -1353,10 +1347,8 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, return; err = xfrm_lookup(&dst, &fl, NULL, 0); - if (err) { - dst_release(dst); + if (err) return; - } rt = (struct rt6_info *) dst; diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 14316c3ebde4..b03e87adca93 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c @@ -100,11 +100,8 @@ static void send_reset(struct sk_buff *oldskb) dst = ip6_route_output(NULL, &fl); if (dst == NULL) return; - if (dst->error || - xfrm_lookup(&dst, &fl, NULL, 0)) { - dst_release(dst); + if (dst->error || xfrm_lookup(&dst, &fl, NULL, 0)) return; - } hh_len = (dst->dev->hard_header_len + 15)&~15; nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr) diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index ed3a76b30fd9..5aa3691c578d 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -655,6 +655,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct flowi fl; int addr_len = msg->msg_namelen; int hlimit = -1; + int tclass = -1; u16 proto; int err; @@ -740,7 +741,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, memset(opt, 0, sizeof(struct ipv6_txoptions)); opt->tot_len = sizeof(struct ipv6_txoptions); - err = datagram_send_ctl(msg, &fl, opt, &hlimit); + err = datagram_send_ctl(msg, &fl, opt, &hlimit, &tclass); if (err < 0) { fl6_sock_release(flowlabel); return err; @@ -755,8 +756,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, } if (opt == NULL) opt = np->opt; - if (flowlabel) - opt = fl6_merge_options(&opt_space, flowlabel, opt); + opt = fl6_merge_options(&opt_space, flowlabel, opt); fl.proto = proto; rawv6_probe_proto_opt(&fl, msg); @@ -782,10 +782,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) { - dst_release(dst); + if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) goto out; - } if (hlimit < 0) { if (ipv6_addr_is_multicast(&fl.fl6_dst)) @@ -798,6 +796,12 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, hlimit = ipv6_get_hoplimit(dst->dev); } + if (tclass < 0) { + tclass = np->cork.tclass; + if (tclass < 0) + tclass = 0; + } + if (msg->msg_flags&MSG_CONFIRM) goto do_confirm; @@ -806,8 +810,9 @@ back_from_confirm: err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl, (struct rt6_info*)dst, msg->msg_flags); } else { lock_sock(sk); - err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, len, 0, - hlimit, opt, &fl, (struct rt6_info*)dst, msg->msg_flags); + err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, + len, 0, hlimit, tclass, opt, &fl, (struct rt6_info*)dst, + msg->msg_flags); if (err) ip6_flush_pending_frames(sk); diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 9d9e04344c77..e4fe9ee484dd 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -479,12 +479,9 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, /* Point into the IP datagram 'data' part. */ if (!pskb_pull(skb, (u8 *) (fhdr + 1) - skb->data)) goto err; - if (end-offset < skb->len) { - if (pskb_trim(skb, end - offset)) - goto err; - if (skb->ip_summed != CHECKSUM_UNNECESSARY) - skb->ip_summed = CHECKSUM_NONE; - } + + if (pskb_trim_rcsum(skb, end - offset)) + goto err; /* Find out which fragments are in front and at the back of us * in the chain of fragments so far. We must know where to put diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 794734f1d230..80643e6b346b 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -632,10 +632,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) { - dst_release(dst); + if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) goto failure; - } if (saddr == NULL) { saddr = &fl.fl6_src; @@ -849,7 +847,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, if (dst == NULL) { opt = np->opt; if (opt == NULL && - np->rxopt.bits.srcrt == 2 && + np->rxopt.bits.osrcrt == 2 && treq->pktopts) { struct sk_buff *pktopts = treq->pktopts; struct inet6_skb_parm *rxopt = IP6CB(pktopts); @@ -888,7 +886,6 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, } done: - dst_release(dst); if (opt && opt != np->opt) sock_kfree_s(sk, opt, opt->tot_len); return err; @@ -915,11 +912,10 @@ static int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb) struct inet6_skb_parm *opt = IP6CB(skb); if (np->rxopt.all) { - if ((opt->hop && np->rxopt.bits.hopopts) || - ((IPV6_FLOWINFO_MASK&*(u32*)skb->nh.raw) && - np->rxopt.bits.rxflow) || - (opt->srcrt && np->rxopt.bits.srcrt) || - ((opt->dst1 || opt->dst0) && np->rxopt.bits.dstopts)) + if ((opt->hop && (np->rxopt.bits.hopopts || np->rxopt.bits.ohopopts)) || + ((IPV6_FLOWINFO_MASK & *(u32*)skb->nh.raw) && np->rxopt.bits.rxflow) || + (opt->srcrt && (np->rxopt.bits.srcrt || np->rxopt.bits.osrcrt)) || + ((opt->dst1 || opt->dst0) && (np->rxopt.bits.dstopts || np->rxopt.bits.odstopts))) return 1; } return 0; @@ -1001,10 +997,8 @@ static void tcp_v6_send_reset(struct sk_buff *skb) /* sk = NULL, but it is safe for now. RST socket required. */ if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { - if ((xfrm_lookup(&buff->dst, &fl, NULL, 0)) < 0) { - dst_release(buff->dst); + if ((xfrm_lookup(&buff->dst, &fl, NULL, 0)) < 0) return; - } ip6_xmit(NULL, buff, &fl, NULL, 0); TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); @@ -1068,10 +1062,8 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 fl.fl_ip_sport = t1->source; if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { - if ((xfrm_lookup(&buff->dst, &fl, NULL, 0)) < 0) { - dst_release(buff->dst); + if ((xfrm_lookup(&buff->dst, &fl, NULL, 0)) < 0) return; - } ip6_xmit(NULL, buff, &fl, NULL, 0); TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); return; @@ -1190,8 +1182,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) TCP_ECN_create_request(req, skb->h.th); treq->pktopts = NULL; if (ipv6_opt_accepted(sk, skb) || - np->rxopt.bits.rxinfo || - np->rxopt.bits.rxhlim) { + np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || + np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { atomic_inc(&skb->users); treq->pktopts = skb; } @@ -1288,7 +1280,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, if (sk_acceptq_is_full(sk)) goto out_overflow; - if (np->rxopt.bits.srcrt == 2 && + if (np->rxopt.bits.osrcrt == 2 && opt == NULL && treq->pktopts) { struct inet6_skb_parm *rxopt = IP6CB(treq->pktopts); if (rxopt->srcrt) @@ -1544,9 +1536,9 @@ ipv6_pktoptions: tp = tcp_sk(sk); if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt && !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) { - if (np->rxopt.bits.rxinfo) + if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo) np->mcast_oif = inet6_iif(opt_skb); - if (np->rxopt.bits.rxhlim) + if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) np->mcast_hops = opt_skb->nh.ipv6h->hop_limit; if (ipv6_opt_accepted(sk, opt_skb)) { skb_set_owner_r(opt_skb, sk); @@ -1734,7 +1726,6 @@ static int tcp_v6_rebuild_header(struct sock *sk) if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) { sk->sk_err_soft = -err; - dst_release(dst); return err; } @@ -1787,7 +1778,6 @@ static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok) if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) { sk->sk_route_caps = 0; - dst_release(dst); return err; } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 390d750449ce..69b146843a20 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -483,7 +483,7 @@ static int udpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) } if (ulen < skb->len) { - if (__pskb_trim(skb, ulen)) + if (pskb_trim_rcsum(skb, ulen)) goto discard; saddr = &skb->nh.ipv6h->saddr; daddr = &skb->nh.ipv6h->daddr; @@ -637,6 +637,7 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, int addr_len = msg->msg_namelen; int ulen = len; int hlimit = -1; + int tclass = -1; int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; int err; @@ -758,7 +759,7 @@ do_udp_sendmsg: memset(opt, 0, sizeof(struct ipv6_txoptions)); opt->tot_len = sizeof(*opt); - err = datagram_send_ctl(msg, fl, opt, &hlimit); + err = datagram_send_ctl(msg, fl, opt, &hlimit, &tclass); if (err < 0) { fl6_sock_release(flowlabel); return err; @@ -773,8 +774,7 @@ do_udp_sendmsg: } if (opt == NULL) opt = np->opt; - if (flowlabel) - opt = fl6_merge_options(&opt_space, flowlabel, opt); + opt = fl6_merge_options(&opt_space, flowlabel, opt); fl->proto = IPPROTO_UDP; ipv6_addr_copy(&fl->fl6_dst, daddr); @@ -799,10 +799,8 @@ do_udp_sendmsg: if (final_p) ipv6_addr_copy(&fl->fl6_dst, final_p); - if ((err = xfrm_lookup(&dst, fl, sk, 0)) < 0) { - dst_release(dst); + if ((err = xfrm_lookup(&dst, fl, sk, 0)) < 0) goto out; - } if (hlimit < 0) { if (ipv6_addr_is_multicast(&fl->fl6_dst)) @@ -815,6 +813,12 @@ do_udp_sendmsg: hlimit = ipv6_get_hoplimit(dst->dev); } + if (tclass < 0) { + tclass = np->tclass; + if (tclass < 0) + tclass = 0; + } + if (msg->msg_flags&MSG_CONFIRM) goto do_confirm; back_from_confirm: @@ -834,9 +838,10 @@ back_from_confirm: do_append_data: up->len += ulen; - err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, sizeof(struct udphdr), - hlimit, opt, fl, (struct rt6_info*)dst, - corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); + err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, + sizeof(struct udphdr), hlimit, tclass, opt, fl, + (struct rt6_info*)dst, + corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); if (err) udp_v6_flush_pending_frames(sk); else if (!corkreq) diff --git a/net/rose/rose_subr.c b/net/rose/rose_subr.c index 02891ce2db37..36a77944622b 100644 --- a/net/rose/rose_subr.c +++ b/net/rose/rose_subr.c @@ -337,13 +337,13 @@ static int rose_parse_ccitt(unsigned char *p, struct rose_facilities_struct *fac memcpy(&facilities->source_addr, p + 7, ROSE_ADDR_LEN); memcpy(callsign, p + 12, l - 10); callsign[l - 10] = '\0'; - facilities->source_call = *asc2ax(callsign); + asc2ax(&facilities->source_call, callsign); } if (*p == FAC_CCITT_SRC_NSAP) { memcpy(&facilities->dest_addr, p + 7, ROSE_ADDR_LEN); memcpy(callsign, p + 12, l - 10); callsign[l - 10] = '\0'; - facilities->dest_call = *asc2ax(callsign); + asc2ax(&facilities->dest_call, callsign); } p += l + 2; n += l + 2; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 83c8135e1764..fda737d77edc 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -765,8 +765,8 @@ restart: switch (policy->action) { case XFRM_POLICY_BLOCK: /* Prohibit the flow */ - xfrm_pol_put(policy); - return -EPERM; + err = -EPERM; + goto error; case XFRM_POLICY_ALLOW: if (policy->xfrm_nr == 0) { @@ -782,8 +782,8 @@ restart: */ dst = xfrm_find_bundle(fl, policy, family); if (IS_ERR(dst)) { - xfrm_pol_put(policy); - return PTR_ERR(dst); + err = PTR_ERR(dst); + goto error; } if (dst) |