Commit b22d1b6a authored by Ralf Baechle's avatar Ralf Baechle

Merge branch 'mti-next' of...

Merge branch 'mti-next' of git://git.linux-mips.org/pub/scm/sjhill/linux-sjhill into mips-for-linux-next
parents 5e0e61dd 0ab2b7d0
...@@ -336,6 +336,7 @@ config MIPS_SEAD3 ...@@ -336,6 +336,7 @@ config MIPS_SEAD3
select BOOT_RAW select BOOT_RAW
select CEVT_R4K select CEVT_R4K
select CSRC_R4K select CSRC_R4K
select CSRC_GIC
select CPU_MIPSR2_IRQ_VI select CPU_MIPSR2_IRQ_VI
select CPU_MIPSR2_IRQ_EI select CPU_MIPSR2_IRQ_EI
select DMA_NONCOHERENT select DMA_NONCOHERENT
...@@ -352,6 +353,7 @@ config MIPS_SEAD3 ...@@ -352,6 +353,7 @@ config MIPS_SEAD3
select SYS_SUPPORTS_BIG_ENDIAN select SYS_SUPPORTS_BIG_ENDIAN
select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_SUPPORTS_SMARTMIPS select SYS_SUPPORTS_SMARTMIPS
select SYS_SUPPORTS_MICROMIPS
select USB_ARCH_HAS_EHCI select USB_ARCH_HAS_EHCI
select USB_EHCI_BIG_ENDIAN_DESC select USB_EHCI_BIG_ENDIAN_DESC
select USB_EHCI_BIG_ENDIAN_MMIO select USB_EHCI_BIG_ENDIAN_MMIO
...@@ -908,6 +910,9 @@ config CEVT_GT641XX ...@@ -908,6 +910,9 @@ config CEVT_GT641XX
config CEVT_R4K config CEVT_R4K
bool bool
config CEVT_GIC
bool
config CEVT_SB1250 config CEVT_SB1250
bool bool
...@@ -1824,6 +1829,15 @@ config FORCE_MAX_ZONEORDER ...@@ -1824,6 +1829,15 @@ config FORCE_MAX_ZONEORDER
The page size is not necessarily 4KB. Keep this in mind The page size is not necessarily 4KB. Keep this in mind
when choosing a value for this option. when choosing a value for this option.
config CEVT_GIC
bool "Use GIC global counter for clock events"
depends on IRQ_GIC && !(MIPS_SEAD3 || MIPS_MT_SMTC)
help
Use the GIC global counter for the clock events. The R4K clock
event driver is always present, so if the platform ends up not
detecting a GIC, it will fall back to the R4K timer for the
generation of clock events.
config BOARD_SCACHE config BOARD_SCACHE
bool bool
...@@ -2048,6 +2062,13 @@ config CPU_HAS_SMARTMIPS ...@@ -2048,6 +2062,13 @@ config CPU_HAS_SMARTMIPS
you don't know you probably don't have SmartMIPS and should say N you don't know you probably don't have SmartMIPS and should say N
here. here.
config CPU_MICROMIPS
depends on SYS_SUPPORTS_MICROMIPS
bool "Build kernel using microMIPS ISA"
help
When this option is enabled the kernel will be built using the
microMIPS ISA
config CPU_HAS_WB config CPU_HAS_WB
bool bool
...@@ -2110,6 +2131,9 @@ config SYS_SUPPORTS_HIGHMEM ...@@ -2110,6 +2131,9 @@ config SYS_SUPPORTS_HIGHMEM
config SYS_SUPPORTS_SMARTMIPS config SYS_SUPPORTS_SMARTMIPS
bool bool
config SYS_SUPPORTS_MICROMIPS
bool
config ARCH_FLATMEM_ENABLE config ARCH_FLATMEM_ENABLE
def_bool y def_bool y
depends on !NUMA && !CPU_LOONGSON2 depends on !NUMA && !CPU_LOONGSON2
......
...@@ -114,6 +114,7 @@ cflags-$(CONFIG_CPU_BIG_ENDIAN) += $(shell $(CC) -dumpmachine |grep -q 'mips.*e ...@@ -114,6 +114,7 @@ cflags-$(CONFIG_CPU_BIG_ENDIAN) += $(shell $(CC) -dumpmachine |grep -q 'mips.*e
cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' || echo -EL $(undef-all) $(predef-le)) cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' || echo -EL $(undef-all) $(predef-le))
cflags-$(CONFIG_CPU_HAS_SMARTMIPS) += $(call cc-option,-msmartmips) cflags-$(CONFIG_CPU_HAS_SMARTMIPS) += $(call cc-option,-msmartmips)
cflags-$(CONFIG_CPU_MICROMIPS) += $(call cc-option,-mmicromips -mno-jals)
cflags-$(CONFIG_SB1XXX_CORELIS) += $(call cc-option,-mno-sched-prolog) \ cflags-$(CONFIG_SB1XXX_CORELIS) += $(call cc-option,-mno-sched-prolog) \
-fno-omit-frame-pointer -fno-omit-frame-pointer
......
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/mach-ar7/ar7.h> #include <asm/mach-ar7/ar7.h>
#include <asm/mips-boards/prom.h>
static int __init memsize(void) static int __init memsize(void)
{ {
......
...@@ -2,30 +2,21 @@ CONFIG_MIPS_MALTA=y ...@@ -2,30 +2,21 @@ CONFIG_MIPS_MALTA=y
CONFIG_CPU_LITTLE_ENDIAN=y CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32_R2=y CONFIG_CPU_MIPS32_R2=y
CONFIG_MIPS_MT_SMP=y CONFIG_MIPS_MT_SMP=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_HZ_100=y CONFIG_HZ_100=y
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y CONFIG_SYSVIPC=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_LOG_BUF_SHIFT=15 CONFIG_LOG_BUF_SHIFT=15
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_RELAY=y
CONFIG_NAMESPACES=y CONFIG_NAMESPACES=y
CONFIG_UTS_NS=y CONFIG_RELAY=y
CONFIG_IPC_NS=y
CONFIG_PID_NS=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_EXPERT=y CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_COMPAT_BRK is not set # CONFIG_COMPAT_BRK is not set
CONFIG_SLAB=y CONFIG_SLAB=y
CONFIG_MODULES=y CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y CONFIG_MODULE_SRCVERSION_ALL=y
# CONFIG_BLK_DEV_BSG is not set
CONFIG_PCI=y CONFIG_PCI=y
CONFIG_PM=y
CONFIG_PACKET=y CONFIG_PACKET=y
CONFIG_UNIX=y CONFIG_UNIX=y
CONFIG_XFRM_USER=m CONFIG_XFRM_USER=m
...@@ -41,8 +32,6 @@ CONFIG_IP_PNP=y ...@@ -41,8 +32,6 @@ CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y CONFIG_IP_PNP_BOOTP=y
CONFIG_NET_IPIP=m CONFIG_NET_IPIP=m
CONFIG_NET_IPGRE=m
CONFIG_NET_IPGRE_BROADCAST=y
CONFIG_IP_MROUTE=y CONFIG_IP_MROUTE=y
CONFIG_IP_PIMSM_V1=y CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y CONFIG_IP_PIMSM_V2=y
...@@ -65,7 +54,6 @@ CONFIG_IPV6_MROUTE=y ...@@ -65,7 +54,6 @@ CONFIG_IPV6_MROUTE=y
CONFIG_IPV6_PIMSM_V2=y CONFIG_IPV6_PIMSM_V2=y
CONFIG_NETWORK_SECMARK=y CONFIG_NETWORK_SECMARK=y
CONFIG_NETFILTER=y CONFIG_NETFILTER=y
CONFIG_NETFILTER_NETLINK_QUEUE=m
CONFIG_NF_CONNTRACK=m CONFIG_NF_CONNTRACK=m
CONFIG_NF_CONNTRACK_SECMARK=y CONFIG_NF_CONNTRACK_SECMARK=y
CONFIG_NF_CONNTRACK_EVENTS=y CONFIG_NF_CONNTRACK_EVENTS=y
...@@ -136,23 +124,15 @@ CONFIG_IP_VS_DH=m ...@@ -136,23 +124,15 @@ CONFIG_IP_VS_DH=m
CONFIG_IP_VS_SH=m CONFIG_IP_VS_SH=m
CONFIG_IP_VS_SED=m CONFIG_IP_VS_SED=m
CONFIG_IP_VS_NQ=m CONFIG_IP_VS_NQ=m
CONFIG_IP_VS_FTP=m
CONFIG_NF_CONNTRACK_IPV4=m CONFIG_NF_CONNTRACK_IPV4=m
CONFIG_IP_NF_QUEUE=m CONFIG_IP_NF_QUEUE=m
CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_ADDRTYPE=m
CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_ECN=m CONFIG_IP_NF_MATCH_ECN=m
CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_MATCH_TTL=m
CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_FILTER=m
CONFIG_IP_NF_TARGET_REJECT=m CONFIG_IP_NF_TARGET_REJECT=m
CONFIG_IP_NF_TARGET_LOG=m
CONFIG_IP_NF_TARGET_ULOG=m CONFIG_IP_NF_TARGET_ULOG=m
CONFIG_NF_NAT=m
CONFIG_IP_NF_TARGET_MASQUERADE=m
CONFIG_IP_NF_TARGET_NETMAP=m
CONFIG_IP_NF_TARGET_REDIRECT=m
CONFIG_NF_NAT_SNMP_BASIC=m
CONFIG_IP_NF_MANGLE=m CONFIG_IP_NF_MANGLE=m
CONFIG_IP_NF_TARGET_CLUSTERIP=m CONFIG_IP_NF_TARGET_CLUSTERIP=m
CONFIG_IP_NF_TARGET_ECN=m CONFIG_IP_NF_TARGET_ECN=m
...@@ -162,8 +142,6 @@ CONFIG_IP_NF_ARPTABLES=m ...@@ -162,8 +142,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m CONFIG_NF_CONNTRACK_IPV6=m
CONFIG_IP6_NF_QUEUE=m
CONFIG_IP6_NF_IPTABLES=m
CONFIG_IP6_NF_MATCH_AH=m CONFIG_IP6_NF_MATCH_AH=m
CONFIG_IP6_NF_MATCH_EUI64=m CONFIG_IP6_NF_MATCH_EUI64=m
CONFIG_IP6_NF_MATCH_FRAG=m CONFIG_IP6_NF_MATCH_FRAG=m
...@@ -173,7 +151,6 @@ CONFIG_IP6_NF_MATCH_IPV6HEADER=m ...@@ -173,7 +151,6 @@ CONFIG_IP6_NF_MATCH_IPV6HEADER=m
CONFIG_IP6_NF_MATCH_MH=m CONFIG_IP6_NF_MATCH_MH=m
CONFIG_IP6_NF_MATCH_RT=m CONFIG_IP6_NF_MATCH_RT=m
CONFIG_IP6_NF_TARGET_HL=m CONFIG_IP6_NF_TARGET_HL=m
CONFIG_IP6_NF_TARGET_LOG=m
CONFIG_IP6_NF_FILTER=m CONFIG_IP6_NF_FILTER=m
CONFIG_IP6_NF_TARGET_REJECT=m CONFIG_IP6_NF_TARGET_REJECT=m
CONFIG_IP6_NF_MANGLE=m CONFIG_IP6_NF_MANGLE=m
...@@ -247,12 +224,10 @@ CONFIG_MAC80211=m ...@@ -247,12 +224,10 @@ CONFIG_MAC80211=m
CONFIG_MAC80211_RC_PID=y CONFIG_MAC80211_RC_PID=y
CONFIG_MAC80211_RC_DEFAULT_PID=y CONFIG_MAC80211_RC_DEFAULT_PID=y
CONFIG_MAC80211_MESH=y CONFIG_MAC80211_MESH=y
CONFIG_MAC80211_LEDS=y
CONFIG_RFKILL=m CONFIG_RFKILL=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=m CONFIG_CONNECTOR=m
CONFIG_MTD=y CONFIG_MTD=y
CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CHAR=y CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y CONFIG_MTD_BLOCK=y
CONFIG_MTD_OOPS=m CONFIG_MTD_OOPS=m
...@@ -271,7 +246,6 @@ CONFIG_BLK_DEV_NBD=m ...@@ -271,7 +246,6 @@ CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM=y
CONFIG_CDROM_PKTCDVD=m CONFIG_CDROM_PKTCDVD=m
CONFIG_ATA_OVER_ETH=m CONFIG_ATA_OVER_ETH=m
# CONFIG_MISC_DEVICES is not set
CONFIG_IDE=y CONFIG_IDE=y
CONFIG_BLK_DEV_IDECD=y CONFIG_BLK_DEV_IDECD=y
CONFIG_IDE_GENERIC=y CONFIG_IDE_GENERIC=y
...@@ -317,13 +291,19 @@ CONFIG_DM_MIRROR=m ...@@ -317,13 +291,19 @@ CONFIG_DM_MIRROR=m
CONFIG_DM_ZERO=m CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m CONFIG_DM_MULTIPATH=m
CONFIG_NETDEVICES=y CONFIG_NETDEVICES=y
CONFIG_IFB=m
CONFIG_DUMMY=m
CONFIG_BONDING=m CONFIG_BONDING=m
CONFIG_MACVLAN=m CONFIG_DUMMY=m
CONFIG_EQUALIZER=m CONFIG_EQUALIZER=m
CONFIG_IFB=m
CONFIG_MACVLAN=m
CONFIG_TUN=m CONFIG_TUN=m
CONFIG_VETH=m CONFIG_VETH=m
# CONFIG_NET_VENDOR_3COM is not set
CONFIG_PCNET32=y
CONFIG_CHELSIO_T3=m
CONFIG_AX88796=m
CONFIG_NETXEN_NIC=m
CONFIG_TC35815=m
CONFIG_MARVELL_PHY=m CONFIG_MARVELL_PHY=m
CONFIG_DAVICOM_PHY=m CONFIG_DAVICOM_PHY=m
CONFIG_QSEMI_PHY=m CONFIG_QSEMI_PHY=m
...@@ -334,14 +314,6 @@ CONFIG_SMSC_PHY=m ...@@ -334,14 +314,6 @@ CONFIG_SMSC_PHY=m
CONFIG_BROADCOM_PHY=m CONFIG_BROADCOM_PHY=m
CONFIG_ICPLUS_PHY=m CONFIG_ICPLUS_PHY=m
CONFIG_REALTEK_PHY=m CONFIG_REALTEK_PHY=m
CONFIG_MDIO_BITBANG=m
CONFIG_NET_ETHERNET=y
CONFIG_AX88796=m
CONFIG_NET_PCI=y
CONFIG_PCNET32=y
CONFIG_TC35815=m
CONFIG_CHELSIO_T3=m
CONFIG_NETXEN_NIC=m
CONFIG_ATMEL=m CONFIG_ATMEL=m
CONFIG_PCI_ATMEL=m CONFIG_PCI_ATMEL=m
CONFIG_PRISM54=m CONFIG_PRISM54=m
...@@ -352,15 +324,7 @@ CONFIG_HOSTAP_PLX=m ...@@ -352,15 +324,7 @@ CONFIG_HOSTAP_PLX=m
CONFIG_HOSTAP_PCI=m CONFIG_HOSTAP_PCI=m
CONFIG_IPW2100=m CONFIG_IPW2100=m
CONFIG_IPW2100_MONITOR=y CONFIG_IPW2100_MONITOR=y
CONFIG_IPW2200=m
CONFIG_IPW2200_MONITOR=y
CONFIG_IPW2200_PROMISCUOUS=y
CONFIG_IPW2200_QOS=y
CONFIG_LIBERTAS=m CONFIG_LIBERTAS=m
CONFIG_HERMES=m
CONFIG_PLX_HERMES=m
CONFIG_TMD_HERMES=m
CONFIG_NORTEL_HERMES=m
# CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set # CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO_I8042 is not set # CONFIG_SERIO_I8042 is not set
...@@ -373,12 +337,6 @@ CONFIG_FB_CIRRUS=y ...@@ -373,12 +337,6 @@ CONFIG_FB_CIRRUS=y
# CONFIG_VGA_CONSOLE is not set # CONFIG_VGA_CONSOLE is not set
CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_HID=m CONFIG_HID=m
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_TRIGGER_TIMER=m
CONFIG_LEDS_TRIGGER_IDE_DISK=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=m
CONFIG_LEDS_TRIGGER_BACKLIGHT=m
CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
CONFIG_RTC_CLASS=y CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_CMOS=y CONFIG_RTC_DRV_CMOS=y
CONFIG_UIO=m CONFIG_UIO=m
...@@ -398,7 +356,6 @@ CONFIG_XFS_QUOTA=y ...@@ -398,7 +356,6 @@ CONFIG_XFS_QUOTA=y
CONFIG_XFS_POSIX_ACL=y CONFIG_XFS_POSIX_ACL=y
CONFIG_QUOTA=y CONFIG_QUOTA=y
CONFIG_QFMT_V2=y CONFIG_QFMT_V2=y
CONFIG_AUTOFS_FS=y
CONFIG_FUSE_FS=m CONFIG_FUSE_FS=m
CONFIG_ISO9660_FS=m CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y CONFIG_JOLIET=y
...@@ -425,7 +382,6 @@ CONFIG_ROMFS_FS=m ...@@ -425,7 +382,6 @@ CONFIG_ROMFS_FS=m
CONFIG_SYSV_FS=m CONFIG_SYSV_FS=m
CONFIG_UFS_FS=m CONFIG_UFS_FS=m
CONFIG_NFS_FS=y CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
CONFIG_ROOT_NFS=y CONFIG_ROOT_NFS=y
CONFIG_NFSD=y CONFIG_NFSD=y
CONFIG_NFSD_V3=y CONFIG_NFSD_V3=y
...@@ -466,7 +422,6 @@ CONFIG_NLS_ISO8859_14=m ...@@ -466,7 +422,6 @@ CONFIG_NLS_ISO8859_14=m
CONFIG_NLS_ISO8859_15=m CONFIG_NLS_ISO8859_15=m
CONFIG_NLS_KOI8_R=m CONFIG_NLS_KOI8_R=m
CONFIG_NLS_KOI8_U=m CONFIG_NLS_KOI8_U=m
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_CRYPTD=m CONFIG_CRYPTO_CRYPTD=m
CONFIG_CRYPTO_LRW=m CONFIG_CRYPTO_LRW=m
......
CONFIG_MIPS_MALTA=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32_R2=y
CONFIG_MIPS_VPE_LOADER=y
CONFIG_MIPS_VPE_APSP_API=y
CONFIG_HZ_100=y
CONFIG_LOCALVERSION="aprp"
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_AUDIT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=15
CONFIG_SYSCTL_SYSCALL=y
CONFIG_EMBEDDED=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
# CONFIG_BLK_DEV_BSG is not set
CONFIG_PCI=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM_USER=m
CONFIG_NET_KEY=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
CONFIG_NET_IPIP=m
CONFIG_IP_MROUTE=y
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
CONFIG_SYN_COOKIES=y
CONFIG_INET_AH=m
CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_INET_LRO is not set
CONFIG_IPV6_PRIVACY=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_IPCOMP=m
CONFIG_IPV6_TUNNEL=m
CONFIG_BRIDGE=m
CONFIG_VLAN_8021Q=m
CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
CONFIG_IPDDP_DECAP=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_CBQ=m
CONFIG_NET_SCH_HTB=m
CONFIG_NET_SCH_HFSC=m
CONFIG_NET_SCH_PRIO=m
CONFIG_NET_SCH_RED=m
CONFIG_NET_SCH_SFQ=m
CONFIG_NET_SCH_TEQL=m
CONFIG_NET_SCH_TBF=m
CONFIG_NET_SCH_GRED=m
CONFIG_NET_SCH_DSMARK=m
CONFIG_NET_SCH_NETEM=m
CONFIG_NET_SCH_INGRESS=m
CONFIG_NET_CLS_BASIC=m
CONFIG_NET_CLS_TCINDEX=m
CONFIG_NET_CLS_ROUTE4=m
CONFIG_NET_CLS_FW=m
CONFIG_NET_CLS_U32=m
CONFIG_NET_CLS_RSVP=m
CONFIG_NET_CLS_RSVP6=m
CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=y
CONFIG_NET_CLS_IND=y
# CONFIG_WIRELESS is not set
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_IDE=y
# CONFIG_IDE_PROC_FS is not set
# CONFIG_IDEPCI_PCIBUS_ORDER is not set
CONFIG_BLK_DEV_GENERIC=y
CONFIG_BLK_DEV_PIIX=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_LOWLEVEL is not set
CONFIG_NETDEVICES=y
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_NET_VENDOR_ADAPTEC is not set
# CONFIG_NET_VENDOR_ALTEON is not set
CONFIG_PCNET32=y
# CONFIG_NET_VENDOR_ATHEROS is not set
# CONFIG_NET_VENDOR_BROADCOM is not set
# CONFIG_NET_VENDOR_BROCADE is not set
# CONFIG_NET_VENDOR_CHELSIO is not set
# CONFIG_NET_VENDOR_CISCO is not set
# CONFIG_NET_VENDOR_DEC is not set
# CONFIG_NET_VENDOR_DLINK is not set
# CONFIG_NET_VENDOR_EMULEX is not set
# CONFIG_NET_VENDOR_EXAR is not set
# CONFIG_NET_VENDOR_HP is not set
# CONFIG_NET_VENDOR_INTEL is not set
# CONFIG_NET_VENDOR_MARVELL is not set
# CONFIG_NET_VENDOR_MELLANOX is not set
# CONFIG_NET_VENDOR_MICREL is not set
# CONFIG_NET_VENDOR_MYRI is not set
# CONFIG_NET_VENDOR_NATSEMI is not set
# CONFIG_NET_VENDOR_NVIDIA is not set
# CONFIG_NET_VENDOR_OKI is not set
# CONFIG_NET_PACKET_ENGINE is not set
# CONFIG_NET_VENDOR_QLOGIC is not set
# CONFIG_NET_VENDOR_REALTEK is not set
# CONFIG_NET_VENDOR_RDC is not set
# CONFIG_NET_VENDOR_SEEQ is not set
# CONFIG_NET_VENDOR_SILAN is not set
# CONFIG_NET_VENDOR_SIS is not set
# CONFIG_NET_VENDOR_SMSC is not set
# CONFIG_NET_VENDOR_STMICRO is not set
# CONFIG_NET_VENDOR_SUN is not set
# CONFIG_NET_VENDOR_TEHUTI is not set
# CONFIG_NET_VENDOR_TI is not set
# CONFIG_NET_VENDOR_TOSHIBA is not set
# CONFIG_NET_VENDOR_VIA is not set
# CONFIG_WLAN is not set
# CONFIG_VT is not set
CONFIG_LEGACY_PTY_COUNT=16
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_HW_RANDOM=y
# CONFIG_HWMON is not set
CONFIG_VIDEO_OUTPUT_CONTROL=m
CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
CONFIG_FB_MATROX=y
CONFIG_FB_MATROX_G=y
CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
CONFIG_USB_UHCI_HCD=y
CONFIG_USB_STORAGE=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_LEDS_TRIGGER_IDE_DISK=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_LEDS_TRIGGER_BACKLIGHT=y
CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_CMOS=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
CONFIG_XFS_FS=y
CONFIG_XFS_QUOTA=y
CONFIG_XFS_POSIX_ACL=y
CONFIG_QUOTA=y
CONFIG_QFMT_V2=y
CONFIG_MSDOS_FS=m
CONFIG_VFAT_FS=m
CONFIG_PROC_KCORE=y
CONFIG_TMPFS=y
CONFIG_NFS_FS=y
CONFIG_ROOT_NFS=y
CONFIG_CIFS=m
CONFIG_CIFS_WEAK_PW_HASH=y
CONFIG_CIFS_XATTR=y
CONFIG_CIFS_POSIX=y
CONFIG_NLS_CODEPAGE_437=m
CONFIG_NLS_ISO8859_1=m
# CONFIG_FTRACE is not set
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_TGR192=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAST5=m
CONFIG_CRYPTO_CAST6=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
# CONFIG_CRYPTO_ANSI_CPRNG is not set
# CONFIG_CRYPTO_HW is not set
CONFIG_MIPS_MALTA=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32_R2=y
CONFIG_MIPS_MT_SMTC=y
# CONFIG_MIPS_MT_FPAFF is not set
CONFIG_NR_CPUS=9
CONFIG_HZ_48=y
CONFIG_LOCALVERSION="smtc"
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_AUDIT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=15
CONFIG_SYSCTL_SYSCALL=y
CONFIG_EMBEDDED=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
# CONFIG_BLK_DEV_BSG is not set
CONFIG_PCI=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM_USER=m
CONFIG_NET_KEY=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
CONFIG_NET_IPIP=m
CONFIG_IP_MROUTE=y
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
CONFIG_SYN_COOKIES=y
CONFIG_INET_AH=m
CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_INET_LRO is not set
CONFIG_IPV6_PRIVACY=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_IPCOMP=m
CONFIG_IPV6_TUNNEL=m
CONFIG_BRIDGE=m
CONFIG_VLAN_8021Q=m
CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
CONFIG_IPDDP_DECAP=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_CBQ=m
CONFIG_NET_SCH_HTB=m
CONFIG_NET_SCH_HFSC=m
CONFIG_NET_SCH_PRIO=m
CONFIG_NET_SCH_RED=m
CONFIG_NET_SCH_SFQ=m
CONFIG_NET_SCH_TEQL=m
CONFIG_NET_SCH_TBF=m
CONFIG_NET_SCH_GRED=m
CONFIG_NET_SCH_DSMARK=m
CONFIG_NET_SCH_NETEM=m
CONFIG_NET_SCH_INGRESS=m
CONFIG_NET_CLS_BASIC=m
CONFIG_NET_CLS_TCINDEX=m
CONFIG_NET_CLS_ROUTE4=m
CONFIG_NET_CLS_FW=m
CONFIG_NET_CLS_U32=m
CONFIG_NET_CLS_RSVP=m
CONFIG_NET_CLS_RSVP6=m
CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=y
CONFIG_NET_CLS_IND=y
# CONFIG_WIRELESS is not set
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_IDE=y
# CONFIG_IDE_PROC_FS is not set
# CONFIG_IDEPCI_PCIBUS_ORDER is not set
CONFIG_BLK_DEV_GENERIC=y
CONFIG_BLK_DEV_PIIX=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_LOWLEVEL is not set
CONFIG_NETDEVICES=y
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_NET_VENDOR_ADAPTEC is not set
# CONFIG_NET_VENDOR_ALTEON is not set
CONFIG_PCNET32=y
# CONFIG_NET_VENDOR_ATHEROS is not set
# CONFIG_NET_VENDOR_BROADCOM is not set
# CONFIG_NET_VENDOR_BROCADE is not set
# CONFIG_NET_VENDOR_CHELSIO is not set
# CONFIG_NET_VENDOR_CISCO is not set
# CONFIG_NET_VENDOR_DEC is not set
# CONFIG_NET_VENDOR_DLINK is not set
# CONFIG_NET_VENDOR_EMULEX is not set
# CONFIG_NET_VENDOR_EXAR is not set
# CONFIG_NET_VENDOR_HP is not set
# CONFIG_NET_VENDOR_INTEL is not set
# CONFIG_NET_VENDOR_MARVELL is not set
# CONFIG_NET_VENDOR_MELLANOX is not set
# CONFIG_NET_VENDOR_MICREL is not set
# CONFIG_NET_VENDOR_MYRI is not set
# CONFIG_NET_VENDOR_NATSEMI is not set
# CONFIG_NET_VENDOR_NVIDIA is not set
# CONFIG_NET_VENDOR_OKI is not set
# CONFIG_NET_PACKET_ENGINE is not set
# CONFIG_NET_VENDOR_QLOGIC is not set
# CONFIG_NET_VENDOR_REALTEK is not set
# CONFIG_NET_VENDOR_RDC is not set
# CONFIG_NET_VENDOR_SEEQ is not set
# CONFIG_NET_VENDOR_SILAN is not set
# CONFIG_NET_VENDOR_SIS is not set
# CONFIG_NET_VENDOR_SMSC is not set
# CONFIG_NET_VENDOR_STMICRO is not set
# CONFIG_NET_VENDOR_SUN is not set
# CONFIG_NET_VENDOR_TEHUTI is not set
# CONFIG_NET_VENDOR_TI is not set
# CONFIG_NET_VENDOR_TOSHIBA is not set
# CONFIG_NET_VENDOR_VIA is not set
# CONFIG_WLAN is not set
# CONFIG_VT is not set
CONFIG_LEGACY_PTY_COUNT=16
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_HW_RANDOM=y
# CONFIG_HWMON is not set
CONFIG_VIDEO_OUTPUT_CONTROL=m
CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
CONFIG_FB_MATROX=y
CONFIG_FB_MATROX_G=y
CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
CONFIG_USB_UHCI_HCD=y
CONFIG_USB_STORAGE=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_LEDS_TRIGGER_IDE_DISK=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_LEDS_TRIGGER_BACKLIGHT=y
CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_CMOS=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
CONFIG_XFS_FS=y
CONFIG_XFS_QUOTA=y
CONFIG_XFS_POSIX_ACL=y
CONFIG_QUOTA=y
CONFIG_QFMT_V2=y
CONFIG_MSDOS_FS=m
CONFIG_VFAT_FS=m
CONFIG_PROC_KCORE=y
CONFIG_TMPFS=y
CONFIG_NFS_FS=y
CONFIG_ROOT_NFS=y
CONFIG_CIFS=m
CONFIG_CIFS_WEAK_PW_HASH=y
CONFIG_CIFS_XATTR=y
CONFIG_CIFS_POSIX=y
CONFIG_NLS_CODEPAGE_437=m
CONFIG_NLS_ISO8859_1=m
# CONFIG_FTRACE is not set
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_TGR192=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAST5=m
CONFIG_CRYPTO_CAST6=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
# CONFIG_CRYPTO_ANSI_CPRNG is not set
# CONFIG_CRYPTO_HW is not set
CONFIG_MIPS_MALTA=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32_R2=y
CONFIG_MIPS_MT_SMP=y
CONFIG_SCHED_SMT=y
CONFIG_MIPS_CMP=y
CONFIG_NR_CPUS=8
CONFIG_HZ_100=y
CONFIG_LOCALVERSION="cmp"
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_AUDIT=y
CONFIG_NO_HZ=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=15
CONFIG_SYSCTL_SYSCALL=y
CONFIG_EMBEDDED=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
# CONFIG_BLK_DEV_BSG is not set
CONFIG_PCI=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM_USER=m
CONFIG_NET_KEY=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
CONFIG_NET_IPIP=m
CONFIG_IP_MROUTE=y
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
CONFIG_SYN_COOKIES=y
CONFIG_INET_AH=m
CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_INET_LRO is not set
CONFIG_IPV6_PRIVACY=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_IPCOMP=m
CONFIG_IPV6_TUNNEL=m
CONFIG_BRIDGE=m
CONFIG_VLAN_8021Q=m
CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
CONFIG_IPDDP_DECAP=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_CBQ=m
CONFIG_NET_SCH_HTB=m
CONFIG_NET_SCH_HFSC=m
CONFIG_NET_SCH_PRIO=m
CONFIG_NET_SCH_RED=m
CONFIG_NET_SCH_SFQ=m
CONFIG_NET_SCH_TEQL=m
CONFIG_NET_SCH_TBF=m
CONFIG_NET_SCH_GRED=m
CONFIG_NET_SCH_DSMARK=m
CONFIG_NET_SCH_NETEM=m
CONFIG_NET_SCH_INGRESS=m
CONFIG_NET_CLS_BASIC=m
CONFIG_NET_CLS_TCINDEX=m
CONFIG_NET_CLS_ROUTE4=m
CONFIG_NET_CLS_FW=m
CONFIG_NET_CLS_U32=m
CONFIG_NET_CLS_RSVP=m
CONFIG_NET_CLS_RSVP6=m
CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=y
CONFIG_NET_CLS_IND=y
# CONFIG_WIRELESS is not set
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_IDE=y
# CONFIG_IDE_PROC_FS is not set
# CONFIG_IDEPCI_PCIBUS_ORDER is not set
CONFIG_BLK_DEV_GENERIC=y
CONFIG_BLK_DEV_PIIX=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_LOWLEVEL is not set
CONFIG_NETDEVICES=y
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_NET_VENDOR_ADAPTEC is not set
# CONFIG_NET_VENDOR_ALTEON is not set
CONFIG_PCNET32=y
# CONFIG_NET_VENDOR_ATHEROS is not set
# CONFIG_NET_VENDOR_BROADCOM is not set
# CONFIG_NET_VENDOR_BROCADE is not set
# CONFIG_NET_VENDOR_CHELSIO is not set
# CONFIG_NET_VENDOR_CISCO is not set
# CONFIG_NET_VENDOR_DEC is not set
# CONFIG_NET_VENDOR_DLINK is not set
# CONFIG_NET_VENDOR_EMULEX is not set
# CONFIG_NET_VENDOR_EXAR is not set
# CONFIG_NET_VENDOR_HP is not set
# CONFIG_NET_VENDOR_INTEL is not set
# CONFIG_NET_VENDOR_MARVELL is not set
# CONFIG_NET_VENDOR_MELLANOX is not set
# CONFIG_NET_VENDOR_MICREL is not set
# CONFIG_NET_VENDOR_MYRI is not set
# CONFIG_NET_VENDOR_NATSEMI is not set
# CONFIG_NET_VENDOR_NVIDIA is not set
# CONFIG_NET_VENDOR_OKI is not set
# CONFIG_NET_PACKET_ENGINE is not set
# CONFIG_NET_VENDOR_QLOGIC is not set
# CONFIG_NET_VENDOR_REALTEK is not set
# CONFIG_NET_VENDOR_RDC is not set
# CONFIG_NET_VENDOR_SEEQ is not set
# CONFIG_NET_VENDOR_SILAN is not set
# CONFIG_NET_VENDOR_SIS is not set
# CONFIG_NET_VENDOR_SMSC is not set
# CONFIG_NET_VENDOR_STMICRO is not set
# CONFIG_NET_VENDOR_SUN is not set
# CONFIG_NET_VENDOR_TEHUTI is not set
# CONFIG_NET_VENDOR_TI is not set
# CONFIG_NET_VENDOR_TOSHIBA is not set
# CONFIG_NET_VENDOR_VIA is not set
# CONFIG_NET_VENDOR_WIZNET is not set
# CONFIG_WLAN is not set
# CONFIG_VT is not set
CONFIG_LEGACY_PTY_COUNT=4
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_HW_RANDOM=y
# CONFIG_HWMON is not set
CONFIG_VIDEO_OUTPUT_CONTROL=m
CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
CONFIG_FB_MATROX=y
CONFIG_FB_MATROX_G=y
CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
CONFIG_USB_UHCI_HCD=y
CONFIG_USB_STORAGE=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_LEDS_TRIGGER_IDE_DISK=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_LEDS_TRIGGER_BACKLIGHT=y
CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_CMOS=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
CONFIG_XFS_FS=y
CONFIG_XFS_QUOTA=y
CONFIG_XFS_POSIX_ACL=y
CONFIG_QUOTA=y
CONFIG_QFMT_V2=y
CONFIG_MSDOS_FS=m
CONFIG_VFAT_FS=m
CONFIG_PROC_KCORE=y
CONFIG_TMPFS=y
CONFIG_NFS_FS=y
CONFIG_ROOT_NFS=y
CONFIG_CIFS=m
CONFIG_CIFS_WEAK_PW_HASH=y
CONFIG_CIFS_XATTR=y
CONFIG_CIFS_POSIX=y
CONFIG_NLS_CODEPAGE_437=m
CONFIG_NLS_ISO8859_1=m
# CONFIG_FTRACE is not set
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_TGR192=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAST5=m
CONFIG_CRYPTO_CAST6=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
# CONFIG_CRYPTO_ANSI_CPRNG is not set
# CONFIG_CRYPTO_HW is not set
CONFIG_MIPS_MALTA=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32_R2=y
CONFIG_HZ_100=y
CONFIG_LOCALVERSION="up"
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_AUDIT=y
CONFIG_NO_HZ=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=15
CONFIG_SYSCTL_SYSCALL=y
CONFIG_EMBEDDED=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
# CONFIG_BLK_DEV_BSG is not set
CONFIG_PCI=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM_USER=m
CONFIG_NET_KEY=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
CONFIG_NET_IPIP=m
CONFIG_IP_MROUTE=y
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
CONFIG_SYN_COOKIES=y
CONFIG_INET_AH=m
CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_INET_LRO is not set
CONFIG_IPV6_PRIVACY=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_IPCOMP=m
CONFIG_IPV6_TUNNEL=m
CONFIG_BRIDGE=m
CONFIG_VLAN_8021Q=m
CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
CONFIG_IPDDP_DECAP=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_CBQ=m
CONFIG_NET_SCH_HTB=m
CONFIG_NET_SCH_HFSC=m
CONFIG_NET_SCH_PRIO=m
CONFIG_NET_SCH_RED=m
CONFIG_NET_SCH_SFQ=m
CONFIG_NET_SCH_TEQL=m
CONFIG_NET_SCH_TBF=m
CONFIG_NET_SCH_GRED=m
CONFIG_NET_SCH_DSMARK=m
CONFIG_NET_SCH_NETEM=m
CONFIG_NET_SCH_INGRESS=m
CONFIG_NET_CLS_BASIC=m
CONFIG_NET_CLS_TCINDEX=m
CONFIG_NET_CLS_ROUTE4=m
CONFIG_NET_CLS_FW=m
CONFIG_NET_CLS_U32=m
CONFIG_NET_CLS_RSVP=m
CONFIG_NET_CLS_RSVP6=m
CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=y
CONFIG_NET_CLS_IND=y
# CONFIG_WIRELESS is not set
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_IDE=y
# CONFIG_IDE_PROC_FS is not set
# CONFIG_IDEPCI_PCIBUS_ORDER is not set
CONFIG_BLK_DEV_GENERIC=y
CONFIG_BLK_DEV_PIIX=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_LOWLEVEL is not set
CONFIG_NETDEVICES=y
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_NET_VENDOR_ADAPTEC is not set
# CONFIG_NET_VENDOR_ALTEON is not set
CONFIG_PCNET32=y
# CONFIG_NET_VENDOR_ATHEROS is not set
# CONFIG_NET_VENDOR_BROADCOM is not set
# CONFIG_NET_VENDOR_BROCADE is not set
# CONFIG_NET_VENDOR_CHELSIO is not set
# CONFIG_NET_VENDOR_CISCO is not set
# CONFIG_NET_VENDOR_DEC is not set
# CONFIG_NET_VENDOR_DLINK is not set
# CONFIG_NET_VENDOR_EMULEX is not set
# CONFIG_NET_VENDOR_EXAR is not set
# CONFIG_NET_VENDOR_HP is not set
# CONFIG_NET_VENDOR_INTEL is not set
# CONFIG_NET_VENDOR_MARVELL is not set
# CONFIG_NET_VENDOR_MELLANOX is not set
# CONFIG_NET_VENDOR_MICREL is not set
# CONFIG_NET_VENDOR_MYRI is not set
# CONFIG_NET_VENDOR_NATSEMI is not set
# CONFIG_NET_VENDOR_NVIDIA is not set
# CONFIG_NET_VENDOR_OKI is not set
# CONFIG_NET_PACKET_ENGINE is not set
# CONFIG_NET_VENDOR_QLOGIC is not set
# CONFIG_NET_VENDOR_REALTEK is not set
# CONFIG_NET_VENDOR_RDC is not set
# CONFIG_NET_VENDOR_SEEQ is not set
# CONFIG_NET_VENDOR_SILAN is not set
# CONFIG_NET_VENDOR_SIS is not set
# CONFIG_NET_VENDOR_SMSC is not set
# CONFIG_NET_VENDOR_STMICRO is not set
# CONFIG_NET_VENDOR_SUN is not set
# CONFIG_NET_VENDOR_TEHUTI is not set
# CONFIG_NET_VENDOR_TI is not set
# CONFIG_NET_VENDOR_TOSHIBA is not set
# CONFIG_NET_VENDOR_VIA is not set
# CONFIG_WLAN is not set
# CONFIG_VT is not set
CONFIG_LEGACY_PTY_COUNT=16
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_HW_RANDOM=y
# CONFIG_HWMON is not set
CONFIG_VIDEO_OUTPUT_CONTROL=m
CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
CONFIG_FB_MATROX=y
CONFIG_FB_MATROX_G=y
CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
CONFIG_USB_UHCI_HCD=y
CONFIG_USB_STORAGE=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_LEDS_TRIGGER_IDE_DISK=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_LEDS_TRIGGER_BACKLIGHT=y
CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_CMOS=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
CONFIG_XFS_FS=y
CONFIG_XFS_QUOTA=y
CONFIG_XFS_POSIX_ACL=y
CONFIG_QUOTA=y
CONFIG_QFMT_V2=y
CONFIG_MSDOS_FS=m
CONFIG_VFAT_FS=m
CONFIG_PROC_KCORE=y
CONFIG_TMPFS=y
CONFIG_NFS_FS=y
CONFIG_ROOT_NFS=y
CONFIG_CIFS=m
CONFIG_CIFS_WEAK_PW_HASH=y
CONFIG_CIFS_XATTR=y
CONFIG_CIFS_POSIX=y
CONFIG_NLS_CODEPAGE_437=m
CONFIG_NLS_ISO8859_1=m
# CONFIG_FTRACE is not set
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_TGR192=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAST5=m
CONFIG_CRYPTO_CAST6=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
# CONFIG_CRYPTO_ANSI_CPRNG is not set
# CONFIG_CRYPTO_HW is not set
...@@ -2,7 +2,6 @@ CONFIG_MIPS_SEAD3=y ...@@ -2,7 +2,6 @@ CONFIG_MIPS_SEAD3=y
CONFIG_CPU_LITTLE_ENDIAN=y CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32_R2=y CONFIG_CPU_MIPS32_R2=y
CONFIG_HZ_100=y CONFIG_HZ_100=y
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y CONFIG_POSIX_MQUEUE=y
CONFIG_NO_HZ=y CONFIG_NO_HZ=y
...@@ -115,10 +114,8 @@ CONFIG_NLS_ISO8859_1=y ...@@ -115,10 +114,8 @@ CONFIG_NLS_ISO8859_1=y
CONFIG_NLS_ISO8859_15=y CONFIG_NLS_ISO8859_15=y
CONFIG_NLS_UTF8=y CONFIG_NLS_UTF8=y
# CONFIG_FTRACE is not set # CONFIG_FTRACE is not set
CONFIG_CRYPTO=y
CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_ECB=y
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_ARC4=y CONFIG_CRYPTO_ARC4=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set # CONFIG_CRYPTO_ANSI_CPRNG is not set
# CONFIG_CRYPTO_HW is not set # CONFIG_CRYPTO_HW is not set
CONFIG_MIPS_SEAD3=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32_R2=y
CONFIG_CPU_MICROMIPS=y
CONFIG_HZ_100=y
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=15
CONFIG_EMBEDDED=y
CONFIG_SLAB=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_MODULES=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
# CONFIG_INET_XFRM_MODE_TUNNEL is not set
# CONFIG_INET_XFRM_MODE_BEET is not set
# CONFIG_INET_LRO is not set
# CONFIG_INET_DIAG is not set
# CONFIG_IPV6 is not set
# CONFIG_WIRELESS is not set
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_CFI=y
CONFIG_MTD_CFI_INTELEXT=y
CONFIG_MTD_PHYSMAP=y
CONFIG_MTD_UBI=y
CONFIG_MTD_UBI_GLUEBI=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_SCSI=y
# CONFIG_SCSI_PROC_FS is not set
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_LOWLEVEL is not set
CONFIG_NETDEVICES=y
CONFIG_SMSC911X=y
# CONFIG_NET_VENDOR_WIZNET is not set
CONFIG_MARVELL_PHY=y
CONFIG_DAVICOM_PHY=y
CONFIG_QSEMI_PHY=y
CONFIG_LXT_PHY=y
CONFIG_CICADA_PHY=y
CONFIG_VITESSE_PHY=y
CONFIG_SMSC_PHY=y
CONFIG_BROADCOM_PHY=y
CONFIG_ICPLUS_PHY=y
# CONFIG_WLAN is not set
# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO is not set
# CONFIG_CONSOLE_TRANSLATIONS is not set
CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_LEGACY_PTY_COUNT=32
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_NR_UARTS=2
CONFIG_SERIAL_8250_RUNTIME_UARTS=2
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
# CONFIG_I2C_COMPAT is not set
CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_HELPER_AUTO is not set
CONFIG_SPI=y
CONFIG_SENSORS_ADT7475=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_LCD_CLASS_DEVICE=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
# CONFIG_VGA_CONSOLE is not set
CONFIG_USB=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
CONFIG_USB_STORAGE=y
CONFIG_MMC=y
CONFIG_MMC_DEBUG=y
CONFIG_MMC_SPI=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_M41T80=y
CONFIG_EXT3_FS=y
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
CONFIG_XFS_FS=y
CONFIG_XFS_QUOTA=y
CONFIG_XFS_POSIX_ACL=y
CONFIG_QUOTA=y
# CONFIG_PRINT_QUOTA_WARNING is not set
CONFIG_MSDOS_FS=m
CONFIG_VFAT_FS=m
CONFIG_TMPFS=y
CONFIG_JFFS2_FS=y
CONFIG_NFS_FS=y
CONFIG_ROOT_NFS=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=y
CONFIG_NLS_ISO8859_15=y
CONFIG_NLS_UTF8=y
# CONFIG_FTRACE is not set
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_ECB=y
CONFIG_CRYPTO_ARC4=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
# CONFIG_CRYPTO_HW is not set
...@@ -2,4 +2,6 @@ ...@@ -2,4 +2,6 @@
# Makefile for generic prom monitor library routines under Linux. # Makefile for generic prom monitor library routines under Linux.
# #
lib-y += cmdline.o
lib-$(CONFIG_64BIT) += call_o32.o lib-$(CONFIG_64BIT) += call_o32.o
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <asm/addrspace.h>
#include <asm/fw/fw.h>
int fw_argc;
int *_fw_argv;
int *_fw_envp;
void __init fw_init_cmdline(void)
{
int i;
/* Validate command line parameters. */
if ((fw_arg0 >= CKSEG0) || (fw_arg1 < CKSEG0)) {
fw_argc = 0;
_fw_argv = NULL;
} else {
fw_argc = (fw_arg0 & 0x0000ffff);
_fw_argv = (int *)fw_arg1;
}
/* Validate environment pointer. */
if (fw_arg2 < CKSEG0)
_fw_envp = NULL;
else
_fw_envp = (int *)fw_arg2;
for (i = 1; i < fw_argc; i++) {
strlcat(arcs_cmdline, fw_argv(i), COMMAND_LINE_SIZE);
if (i < (fw_argc - 1))
strlcat(arcs_cmdline, " ", COMMAND_LINE_SIZE);
}
}
char * __init fw_getcmdline(void)
{
return &(arcs_cmdline[0]);
}
char *fw_getenv(char *envname)
{
char *result = NULL;
if (_fw_envp != NULL) {
/*
* Return a pointer to the given environment variable.
* YAMON uses "name", "value" pairs, while U-Boot uses
* "name=value".
*/
int i, yamon, index = 0;
yamon = (strchr(fw_envp(index), '=') == NULL);
i = strlen(envname);
while (fw_envp(index)) {
if (strncmp(envname, fw_envp(index), i) == 0) {
if (yamon) {
result = fw_envp(index + 1);
break;
} else if (fw_envp(index)[i] == '=') {
result = (fw_envp(index + 1) + i);
break;
}
}
/* Increment array index. */
if (yamon)
index += 2;
else
index += 1;
}
}
return result;
}
unsigned long fw_getenvl(char *envname)
{
unsigned long envl = 0UL;
char *str;
long val;
int tmp;
str = fw_getenv(envname);
if (str) {
tmp = kstrtol(str, 0, &val);
envl = (unsigned long)val;
}
return envl;
}
...@@ -296,6 +296,7 @@ symbol = value ...@@ -296,6 +296,7 @@ symbol = value
#define LONG_SUBU subu #define LONG_SUBU subu
#define LONG_L lw #define LONG_L lw
#define LONG_S sw #define LONG_S sw
#define LONG_SP swp
#define LONG_SLL sll #define LONG_SLL sll
#define LONG_SLLV sllv #define LONG_SLLV sllv
#define LONG_SRL srl #define LONG_SRL srl
...@@ -318,6 +319,7 @@ symbol = value ...@@ -318,6 +319,7 @@ symbol = value
#define LONG_SUBU dsubu #define LONG_SUBU dsubu
#define LONG_L ld #define LONG_L ld
#define LONG_S sd #define LONG_S sd
#define LONG_SP sdp
#define LONG_SLL dsll #define LONG_SLL dsll
#define LONG_SLLV dsllv #define LONG_SLLV dsllv
#define LONG_SRL dsrl #define LONG_SRL dsrl
......
...@@ -11,6 +11,14 @@ ...@@ -11,6 +11,14 @@
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/inst.h> #include <asm/inst.h>
extern int __isa_exception_epc(struct pt_regs *regs);
extern int __compute_return_epc(struct pt_regs *regs);
extern int __compute_return_epc_for_insn(struct pt_regs *regs,
union mips_instruction insn);
extern int __microMIPS_compute_return_epc(struct pt_regs *regs);
extern int __MIPS16e_compute_return_epc(struct pt_regs *regs);
static inline int delay_slot(struct pt_regs *regs) static inline int delay_slot(struct pt_regs *regs)
{ {
return regs->cp0_cause & CAUSEF_BD; return regs->cp0_cause & CAUSEF_BD;
...@@ -18,20 +26,27 @@ static inline int delay_slot(struct pt_regs *regs) ...@@ -18,20 +26,27 @@ static inline int delay_slot(struct pt_regs *regs)
static inline unsigned long exception_epc(struct pt_regs *regs) static inline unsigned long exception_epc(struct pt_regs *regs)
{ {
if (!delay_slot(regs)) if (likely(!delay_slot(regs)))
return regs->cp0_epc; return regs->cp0_epc;
if (get_isa16_mode(regs->cp0_epc))
return __isa_exception_epc(regs);
return regs->cp0_epc + 4; return regs->cp0_epc + 4;
} }
#define BRANCH_LIKELY_TAKEN 0x0001 #define BRANCH_LIKELY_TAKEN 0x0001
extern int __compute_return_epc(struct pt_regs *regs);
extern int __compute_return_epc_for_insn(struct pt_regs *regs,
union mips_instruction insn);
static inline int compute_return_epc(struct pt_regs *regs) static inline int compute_return_epc(struct pt_regs *regs)
{ {
if (get_isa16_mode(regs->cp0_epc)) {
if (cpu_has_mmips)
return __microMIPS_compute_return_epc(regs);
if (cpu_has_mips16)
return __MIPS16e_compute_return_epc(regs);
return regs->cp0_epc;
}
if (!delay_slot(regs)) { if (!delay_slot(regs)) {
regs->cp0_epc += 4; regs->cp0_epc += 4;
return 0; return 0;
...@@ -40,4 +55,19 @@ static inline int compute_return_epc(struct pt_regs *regs) ...@@ -40,4 +55,19 @@ static inline int compute_return_epc(struct pt_regs *regs)
return __compute_return_epc(regs); return __compute_return_epc(regs);
} }
static inline int MIPS16e_compute_return_epc(struct pt_regs *regs,
union mips16e_instruction *inst)
{
if (likely(!delay_slot(regs))) {
if (inst->ri.opcode == MIPS16e_extend_op) {
regs->cp0_epc += 4;
return 0;
}
regs->cp0_epc += 2;
return 0;
}
return __MIPS16e_compute_return_epc(regs);
}
#endif /* _ASM_BRANCH_H */ #endif /* _ASM_BRANCH_H */
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2006 Ralf Baechle <ralf@linux-mips.org>
*
*/
#ifndef __ASM_DMA_COHERENCE_H
#define __ASM_DMA_COHERENCE_H
extern int coherentio;
extern int hw_coherentio;
#endif
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#define _ASM_DMA_MAPPING_H #define _ASM_DMA_MAPPING_H
#include <asm/scatterlist.h> #include <asm/scatterlist.h>
#include <asm/dma-coherence.h>
#include <asm/cache.h> #include <asm/cache.h>
#include <asm-generic/dma-coherent.h> #include <asm-generic/dma-coherent.h>
......
...@@ -54,6 +54,12 @@ do { \ ...@@ -54,6 +54,12 @@ do { \
extern int mips_dsemul(struct pt_regs *regs, mips_instruction ir, extern int mips_dsemul(struct pt_regs *regs, mips_instruction ir,
unsigned long cpc); unsigned long cpc);
extern int do_dsemulret(struct pt_regs *xcp); extern int do_dsemulret(struct pt_regs *xcp);
extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
struct mips_fpu_struct *ctx, int has_fpu,
void *__user *fault_addr);
int process_fpemu_return(int sig, void __user *fault_addr);
int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
unsigned long *contpc);
/* /*
* Instruction inserted following the badinst to further tag the sequence * Instruction inserted following the badinst to further tag the sequence
......
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2012 MIPS Technologies, Inc.
*/
#ifndef __ASM_FW_H_
#define __ASM_FW_H_
#include <asm/bootinfo.h> /* For cleaner code... */
enum fw_memtypes {
fw_dontuse,
fw_code,
fw_free,
};
typedef struct {
unsigned long base; /* Within KSEG0 */
unsigned int size; /* bytes */
enum fw_memtypes type; /* fw_memtypes */
} fw_memblock_t;
/* Maximum number of memory block descriptors. */
#define FW_MAX_MEMBLOCKS 32
extern int fw_argc;
extern int *_fw_argv;
extern int *_fw_envp;
/*
* Most firmware like YAMON, PMON, etc. pass arguments and environment
* variables as 32-bit pointers. These take care of sign extension.
*/
#define fw_argv(index) ((char *)(long)_fw_argv[(index)])
#define fw_envp(index) ((char *)(long)_fw_envp[(index)])
extern void fw_init_cmdline(void);
extern char *fw_getcmdline(void);
extern fw_memblock_t *fw_getmdesc(void);
extern void fw_meminit(void);
extern char *fw_getenv(char *name);
extern unsigned long fw_getenvl(char *name);
extern void fw_init_early_console(char port);
#endif /* __ASM_FW_H_ */
...@@ -202,7 +202,7 @@ ...@@ -202,7 +202,7 @@
#define GIC_VPE_WD_COUNT0_OFS 0x0094 #define GIC_VPE_WD_COUNT0_OFS 0x0094
#define GIC_VPE_WD_INITIAL0_OFS 0x0098 #define GIC_VPE_WD_INITIAL0_OFS 0x0098
#define GIC_VPE_COMPARE_LO_OFS 0x00a0 #define GIC_VPE_COMPARE_LO_OFS 0x00a0
#define GIC_VPE_COMPARE_HI 0x00a4 #define GIC_VPE_COMPARE_HI_OFS 0x00a4
#define GIC_VPE_EIC_SHADOW_SET_BASE 0x0100 #define GIC_VPE_EIC_SHADOW_SET_BASE 0x0100
#define GIC_VPE_EIC_SS(intr) \ #define GIC_VPE_EIC_SS(intr) \
...@@ -359,7 +359,11 @@ struct gic_shared_intr_map { ...@@ -359,7 +359,11 @@ struct gic_shared_intr_map {
/* Mapped interrupt to pin X, then GIC will generate the vector (X+1). */ /* Mapped interrupt to pin X, then GIC will generate the vector (X+1). */
#define GIC_PIN_TO_VEC_OFFSET (1) #define GIC_PIN_TO_VEC_OFFSET (1)
extern int gic_present; #include <linux/clocksource.h>
#include <linux/irq.h>
extern unsigned int gic_present;
extern unsigned int gic_frequency;
extern unsigned long _gic_base; extern unsigned long _gic_base;
extern unsigned int gic_irq_base; extern unsigned int gic_irq_base;
extern unsigned int gic_irq_flags[]; extern unsigned int gic_irq_flags[];
...@@ -368,18 +372,20 @@ extern struct gic_shared_intr_map gic_shared_intr_map[]; ...@@ -368,18 +372,20 @@ extern struct gic_shared_intr_map gic_shared_intr_map[];
extern void gic_init(unsigned long gic_base_addr, extern void gic_init(unsigned long gic_base_addr,
unsigned long gic_addrspace_size, struct gic_intr_map *intrmap, unsigned long gic_addrspace_size, struct gic_intr_map *intrmap,
unsigned int intrmap_size, unsigned int irqbase); unsigned int intrmap_size, unsigned int irqbase);
extern void gic_clocksource_init(unsigned int); extern void gic_clocksource_init(unsigned int);
extern unsigned int gic_get_int(void); extern unsigned int gic_compare_int (void);
extern cycle_t gic_read_count(void);
extern cycle_t gic_read_compare(void);
extern void gic_write_compare(cycle_t cnt);
extern void gic_send_ipi(unsigned int intr); extern void gic_send_ipi(unsigned int intr);
extern unsigned int plat_ipi_call_int_xlate(unsigned int); extern unsigned int plat_ipi_call_int_xlate(unsigned int);
extern unsigned int plat_ipi_resched_int_xlate(unsigned int); extern unsigned int plat_ipi_resched_int_xlate(unsigned int);
extern void gic_bind_eic_interrupt(int irq, int set); extern void gic_bind_eic_interrupt(int irq, int set);
extern unsigned int gic_get_timer_pending(void); extern unsigned int gic_get_timer_pending(void);
extern unsigned int gic_get_int(void);
extern void gic_enable_interrupt(int irq_vec); extern void gic_enable_interrupt(int irq_vec);
extern void gic_disable_interrupt(int irq_vec); extern void gic_disable_interrupt(int irq_vec);
extern void gic_irq_ack(struct irq_data *d); extern void gic_irq_ack(struct irq_data *d);
extern void gic_finish_irq(struct irq_data *d); extern void gic_finish_irq(struct irq_data *d);
extern void gic_platform_init(int irqs, struct irq_chip *irq_controller); extern void gic_platform_init(int irqs, struct irq_chip *irq_controller);
#endif /* _ASM_GICREGS_H */ #endif /* _ASM_GICREGS_H */
...@@ -73,4 +73,16 @@ ...@@ -73,4 +73,16 @@
typedef unsigned int mips_instruction; typedef unsigned int mips_instruction;
/* microMIPS instruction decode structure. Do NOT export!!! */
struct mm_decoded_insn {
mips_instruction insn;
mips_instruction next_insn;
int pc_inc;
int next_pc_inc;
int micro_mips_mode;
};
/* Recode table from 16-bit register notation to 32-bit GPR. Do NOT export!!! */
extern const int reg16to32[];
#endif /* _ASM_INST_H */ #endif /* _ASM_INST_H */
...@@ -336,7 +336,7 @@ enum emulation_result { ...@@ -336,7 +336,7 @@ enum emulation_result {
#define VPN2_MASK 0xffffe000 #define VPN2_MASK 0xffffe000
#define TLB_IS_GLOBAL(x) (((x).tlb_lo0 & MIPS3_PG_G) && ((x).tlb_lo1 & MIPS3_PG_G)) #define TLB_IS_GLOBAL(x) (((x).tlb_lo0 & MIPS3_PG_G) && ((x).tlb_lo1 & MIPS3_PG_G))
#define TLB_VPN2(x) ((x).tlb_hi & VPN2_MASK) #define TLB_VPN2(x) ((x).tlb_hi & VPN2_MASK)
#define TLB_ASID(x) ((x).tlb_hi & ASID_MASK) #define TLB_ASID(x) (ASID_MASK((x).tlb_hi))
#define TLB_IS_VALID(x, va) (((va) & (1 << PAGE_SHIFT)) ? ((x).tlb_lo1 & MIPS3_PG_V) : ((x).tlb_lo0 & MIPS3_PG_V)) #define TLB_IS_VALID(x, va) (((va) & (1 << PAGE_SHIFT)) ? ((x).tlb_lo1 & MIPS3_PG_V) : ((x).tlb_lo0 & MIPS3_PG_V))
struct kvm_mips_tlb { struct kvm_mips_tlb {
......
...@@ -61,9 +61,8 @@ static inline int plat_device_is_coherent(struct device *dev) ...@@ -61,9 +61,8 @@ static inline int plat_device_is_coherent(struct device *dev)
{ {
#ifdef CONFIG_DMA_COHERENT #ifdef CONFIG_DMA_COHERENT
return 1; return 1;
#endif #else
#ifdef CONFIG_DMA_NONCOHERENT return coherentio;
return 0;
#endif #endif
} }
......
...@@ -28,7 +28,11 @@ ...@@ -28,7 +28,11 @@
/* #define cpu_has_prefetch ? */ /* #define cpu_has_prefetch ? */
#define cpu_has_mcheck 1 #define cpu_has_mcheck 1
/* #define cpu_has_ejtag ? */ /* #define cpu_has_ejtag ? */
#ifdef CONFIG_CPU_MICROMIPS
#define cpu_has_llsc 0
#else
#define cpu_has_llsc 1 #define cpu_has_llsc 1
#endif
/* #define cpu_has_vtag_icache ? */ /* #define cpu_has_vtag_icache ? */
/* #define cpu_has_dc_aliases ? */ /* #define cpu_has_dc_aliases ? */
/* #define cpu_has_ic_fills_f_dc ? */ /* #define cpu_has_ic_fills_f_dc ? */
......
...@@ -83,4 +83,7 @@ extern void mips_pcibios_init(void); ...@@ -83,4 +83,7 @@ extern void mips_pcibios_init(void);
#define mips_pcibios_init() do { } while (0) #define mips_pcibios_init() do { } while (0)
#endif #endif
extern void mips_scroll_message(void);
extern void mips_display_message(const char *str);
#endif /* __ASM_MIPS_BOARDS_GENERIC_H */ #endif /* __ASM_MIPS_BOARDS_GENERIC_H */
/*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
*
* ########################################################################
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
* ########################################################################
*
* MIPS boards bootprom interface for the Linux kernel.
*
*/
#ifndef _MIPS_PROM_H
#define _MIPS_PROM_H
extern char *prom_getcmdline(void);
extern char *prom_getenv(char *name);
extern void prom_init_cmdline(void);
extern void prom_meminit(void);
extern void prom_fixup_mem_map(unsigned long start_mem, unsigned long end_mem);
extern void mips_display_message(const char *str);
extern void mips_display_word(unsigned int num);
extern void mips_scroll_message(void);
extern int get_ethernet_addr(char *ethernet_addr);
/* Memory descriptor management. */
#define PROM_MAX_PMEMBLOCKS 32
struct prom_pmemblock {
unsigned long base; /* Within KSEG0. */
unsigned int size; /* In bytes. */
unsigned int type; /* free or prom memory */
};
#endif /* !(_MIPS_PROM_H) */
...@@ -596,6 +596,7 @@ ...@@ -596,6 +596,7 @@
#define MIPS_CONF3_RXI (_ULCAST_(1) << 12) #define MIPS_CONF3_RXI (_ULCAST_(1) << 12)
#define MIPS_CONF3_ULRI (_ULCAST_(1) << 13) #define MIPS_CONF3_ULRI (_ULCAST_(1) << 13)
#define MIPS_CONF3_ISA (_ULCAST_(3) << 14) #define MIPS_CONF3_ISA (_ULCAST_(3) << 14)
#define MIPS_CONF3_ISA_OE (_ULCAST_(3) << 16)
#define MIPS_CONF3_VZ (_ULCAST_(1) << 23) #define MIPS_CONF3_VZ (_ULCAST_(1) << 23)
#define MIPS_CONF4_MMUSIZEEXT (_ULCAST_(255) << 0) #define MIPS_CONF4_MMUSIZEEXT (_ULCAST_(255) << 0)
...@@ -622,6 +623,24 @@ ...@@ -622,6 +623,24 @@
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
/*
* Macros for handling the ISA mode bit for microMIPS.
*/
#define get_isa16_mode(x) ((x) & 0x1)
#define msk_isa16_mode(x) ((x) & ~0x1)
#define set_isa16_mode(x) do { (x) |= 0x1; } while(0)
/*
* microMIPS instructions can be 16-bit or 32-bit in length. This
* returns a 1 if the instruction is 16-bit and a 0 if 32-bit.
*/
static inline int mm_insn_16bit(u16 insn)
{
u16 opcode = (insn >> 10) & 0x7;
return (opcode >= 1 && opcode <= 3) ? 1 : 0;
}
/* /*
* Functions to access the R10000 performance counters. These are basically * Functions to access the R10000 performance counters. These are basically
* mfc0 and mtc0 instructions from and to coprocessor register with a 5-bit * mfc0 and mtc0 instructions from and to coprocessor register with a 5-bit
......
...@@ -67,45 +67,68 @@ extern unsigned long pgd_current[]; ...@@ -67,45 +67,68 @@ extern unsigned long pgd_current[];
TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir) TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
#endif #endif
#endif /* CONFIG_MIPS_PGD_C0_CONTEXT*/ #endif /* CONFIG_MIPS_PGD_C0_CONTEXT*/
#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
#define ASID_INC 0x40 #define ASID_INC(asid) \
#define ASID_MASK 0xfc0 ({ \
unsigned long __asid = asid; \
#elif defined(CONFIG_CPU_R8000) __asm__("1:\taddiu\t%0,1\t\t\t\t# patched\n\t" \
".section\t__asid_inc,\"a\"\n\t" \
#define ASID_INC 0x10 ".word\t1b\n\t" \
#define ASID_MASK 0xff0 ".previous" \
:"=r" (__asid) \
#elif defined(CONFIG_MIPS_MT_SMTC) :"0" (__asid)); \
__asid; \
#define ASID_INC 0x1 })
extern unsigned long smtc_asid_mask; #define ASID_MASK(asid) \
#define ASID_MASK (smtc_asid_mask) ({ \
#define HW_ASID_MASK 0xff unsigned long __asid = asid; \
/* End SMTC/34K debug hack */ __asm__("1:\tandi\t%0,%1,0xfc0\t\t\t# patched\n\t" \
#else /* FIXME: not correct for R6000 */ ".section\t__asid_mask,\"a\"\n\t" \
".word\t1b\n\t" \
#define ASID_INC 0x1 ".previous" \
#define ASID_MASK 0xff :"=r" (__asid) \
:"r" (__asid)); \
__asid; \
})
#define ASID_VERSION_MASK \
({ \
unsigned long __asid; \
__asm__("1:\taddiu\t%0,$0,0xff00\t\t\t\t# patched\n\t" \
".section\t__asid_version_mask,\"a\"\n\t" \
".word\t1b\n\t" \
".previous" \
:"=r" (__asid)); \
__asid; \
})
#define ASID_FIRST_VERSION \
({ \
unsigned long __asid = asid; \
__asm__("1:\tli\t%0,0x100\t\t\t\t# patched\n\t" \
".section\t__asid_first_version,\"a\"\n\t" \
".word\t1b\n\t" \
".previous" \
:"=r" (__asid)); \
__asid; \
})
#define ASID_FIRST_VERSION_R3000 0x1000
#define ASID_FIRST_VERSION_R4000 0x100
#define ASID_FIRST_VERSION_R8000 0x1000
#define ASID_FIRST_VERSION_RM9000 0x1000
#ifdef CONFIG_MIPS_MT_SMTC
#define SMTC_HW_ASID_MASK 0xff
extern unsigned int smtc_asid_mask;
#endif #endif
#define cpu_context(cpu, mm) ((mm)->context.asid[cpu]) #define cpu_context(cpu, mm) ((mm)->context.asid[cpu])
#define cpu_asid(cpu, mm) (cpu_context((cpu), (mm)) & ASID_MASK) #define cpu_asid(cpu, mm) ASID_MASK(cpu_context((cpu), (mm)))
#define asid_cache(cpu) (cpu_data[cpu].asid_cache) #define asid_cache(cpu) (cpu_data[cpu].asid_cache)
static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
{ {
} }
/*
* All unused by hardware upper bits will be considered
* as a software asid extension.
*/
#define ASID_VERSION_MASK ((unsigned long)~(ASID_MASK|(ASID_MASK-1)))
#define ASID_FIRST_VERSION ((unsigned long)(~ASID_VERSION_MASK) + 1)
#ifndef CONFIG_MIPS_MT_SMTC #ifndef CONFIG_MIPS_MT_SMTC
/* Normal, classic MIPS get_new_mmu_context */ /* Normal, classic MIPS get_new_mmu_context */
static inline void static inline void
...@@ -114,7 +137,7 @@ get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) ...@@ -114,7 +137,7 @@ get_new_mmu_context(struct mm_struct *mm, unsigned long cpu)
extern void kvm_local_flush_tlb_all(void); extern void kvm_local_flush_tlb_all(void);
unsigned long asid = asid_cache(cpu); unsigned long asid = asid_cache(cpu);
if (! ((asid += ASID_INC) & ASID_MASK) ) { if (!ASID_MASK((asid = ASID_INC(asid)))) {
if (cpu_has_vtag_icache) if (cpu_has_vtag_icache)
flush_icache_all(); flush_icache_all();
#ifdef CONFIG_VIRTUALIZATION #ifdef CONFIG_VIRTUALIZATION
...@@ -177,7 +200,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, ...@@ -177,7 +200,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
* free up the ASID value for use and flush any old * free up the ASID value for use and flush any old
* instances of it from the TLB. * instances of it from the TLB.
*/ */
oldasid = (read_c0_entryhi() & ASID_MASK); oldasid = ASID_MASK(read_c0_entryhi());
if(smtc_live_asid[mytlb][oldasid]) { if(smtc_live_asid[mytlb][oldasid]) {
smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu); smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu);
if(smtc_live_asid[mytlb][oldasid] == 0) if(smtc_live_asid[mytlb][oldasid] == 0)
...@@ -188,7 +211,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, ...@@ -188,7 +211,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
* having ASID_MASK smaller than the hardware maximum, * having ASID_MASK smaller than the hardware maximum,
* make sure no "soft" bits become "hard"... * make sure no "soft" bits become "hard"...
*/ */
write_c0_entryhi((read_c0_entryhi() & ~HW_ASID_MASK) | write_c0_entryhi((read_c0_entryhi() & ~SMTC_HW_ASID_MASK) |
cpu_asid(cpu, next)); cpu_asid(cpu, next));
ehb(); /* Make sure it propagates to TCStatus */ ehb(); /* Make sure it propagates to TCStatus */
evpe(mtflags); evpe(mtflags);
...@@ -241,15 +264,15 @@ activate_mm(struct mm_struct *prev, struct mm_struct *next) ...@@ -241,15 +264,15 @@ activate_mm(struct mm_struct *prev, struct mm_struct *next)
#ifdef CONFIG_MIPS_MT_SMTC #ifdef CONFIG_MIPS_MT_SMTC
/* See comments for similar code above */ /* See comments for similar code above */
mtflags = dvpe(); mtflags = dvpe();
oldasid = read_c0_entryhi() & ASID_MASK; oldasid = ASID_MASK(read_c0_entryhi());
if(smtc_live_asid[mytlb][oldasid]) { if(smtc_live_asid[mytlb][oldasid]) {
smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu); smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu);
if(smtc_live_asid[mytlb][oldasid] == 0) if(smtc_live_asid[mytlb][oldasid] == 0)
smtc_flush_tlb_asid(oldasid); smtc_flush_tlb_asid(oldasid);
} }
/* See comments for similar code above */ /* See comments for similar code above */
write_c0_entryhi((read_c0_entryhi() & ~HW_ASID_MASK) | write_c0_entryhi((read_c0_entryhi() & ~SMTC_HW_ASID_MASK) |
cpu_asid(cpu, next)); cpu_asid(cpu, next));
ehb(); /* Make sure it propagates to TCStatus */ ehb(); /* Make sure it propagates to TCStatus */
evpe(mtflags); evpe(mtflags);
#else #else
...@@ -286,14 +309,14 @@ drop_mmu_context(struct mm_struct *mm, unsigned cpu) ...@@ -286,14 +309,14 @@ drop_mmu_context(struct mm_struct *mm, unsigned cpu)
#ifdef CONFIG_MIPS_MT_SMTC #ifdef CONFIG_MIPS_MT_SMTC
/* See comments for similar code above */ /* See comments for similar code above */
prevvpe = dvpe(); prevvpe = dvpe();
oldasid = (read_c0_entryhi() & ASID_MASK); oldasid = ASID_MASK(read_c0_entryhi());
if (smtc_live_asid[mytlb][oldasid]) { if (smtc_live_asid[mytlb][oldasid]) {
smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu); smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu);
if(smtc_live_asid[mytlb][oldasid] == 0) if(smtc_live_asid[mytlb][oldasid] == 0)
smtc_flush_tlb_asid(oldasid); smtc_flush_tlb_asid(oldasid);
} }
/* See comments for similar code above */ /* See comments for similar code above */
write_c0_entryhi((read_c0_entryhi() & ~HW_ASID_MASK) write_c0_entryhi((read_c0_entryhi() & ~SMTC_HW_ASID_MASK)
| cpu_asid(cpu, mm)); | cpu_asid(cpu, mm));
ehb(); /* Make sure it propagates to TCStatus */ ehb(); /* Make sure it propagates to TCStatus */
evpe(prevvpe); evpe(prevvpe);
......
...@@ -139,7 +139,7 @@ ...@@ -139,7 +139,7 @@
1: move ra, k0 1: move ra, k0
li k0, 3 li k0, 3
mtc0 k0, $22 mtc0 k0, $22
#endif /* CONFIG_CPU_LOONGSON2F */ #endif /* CONFIG_CPU_JUMP_WORKAROUNDS */
#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32) #if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
lui k1, %hi(kernelsp) lui k1, %hi(kernelsp)
#else #else
...@@ -189,6 +189,7 @@ ...@@ -189,6 +189,7 @@
LONG_S $0, PT_R0(sp) LONG_S $0, PT_R0(sp)
mfc0 v1, CP0_STATUS mfc0 v1, CP0_STATUS
LONG_S $2, PT_R2(sp) LONG_S $2, PT_R2(sp)
LONG_S v1, PT_STATUS(sp)
#ifdef CONFIG_MIPS_MT_SMTC #ifdef CONFIG_MIPS_MT_SMTC
/* /*
* Ideally, these instructions would be shuffled in * Ideally, these instructions would be shuffled in
...@@ -200,21 +201,20 @@ ...@@ -200,21 +201,20 @@
LONG_S k0, PT_TCSTATUS(sp) LONG_S k0, PT_TCSTATUS(sp)
#endif /* CONFIG_MIPS_MT_SMTC */ #endif /* CONFIG_MIPS_MT_SMTC */
LONG_S $4, PT_R4(sp) LONG_S $4, PT_R4(sp)
LONG_S $5, PT_R5(sp)
LONG_S v1, PT_STATUS(sp)
mfc0 v1, CP0_CAUSE mfc0 v1, CP0_CAUSE
LONG_S $6, PT_R6(sp) LONG_S $5, PT_R5(sp)
LONG_S $7, PT_R7(sp)
LONG_S v1, PT_CAUSE(sp) LONG_S v1, PT_CAUSE(sp)
LONG_S $6, PT_R6(sp)
MFC0 v1, CP0_EPC MFC0 v1, CP0_EPC
LONG_S $7, PT_R7(sp)
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
LONG_S $8, PT_R8(sp) LONG_S $8, PT_R8(sp)
LONG_S $9, PT_R9(sp) LONG_S $9, PT_R9(sp)
#endif #endif
LONG_S v1, PT_EPC(sp)
LONG_S $25, PT_R25(sp) LONG_S $25, PT_R25(sp)
LONG_S $28, PT_R28(sp) LONG_S $28, PT_R28(sp)
LONG_S $31, PT_R31(sp) LONG_S $31, PT_R31(sp)
LONG_S v1, PT_EPC(sp)
ori $28, sp, _THREAD_MASK ori $28, sp, _THREAD_MASK
xori $28, _THREAD_MASK xori $28, _THREAD_MASK
#ifdef CONFIG_CPU_CAVIUM_OCTEON #ifdef CONFIG_CPU_CAVIUM_OCTEON
......
...@@ -52,13 +52,15 @@ extern int (*perf_irq)(void); ...@@ -52,13 +52,15 @@ extern int (*perf_irq)(void);
*/ */
extern unsigned int __weak get_c0_compare_int(void); extern unsigned int __weak get_c0_compare_int(void);
extern int r4k_clockevent_init(void); extern int r4k_clockevent_init(void);
extern int smtc_clockevent_init(void);
extern int gic_clockevent_init(void);
static inline int mips_clockevent_init(void) static inline int mips_clockevent_init(void)
{ {
#ifdef CONFIG_MIPS_MT_SMTC #ifdef CONFIG_MIPS_MT_SMTC
extern int smtc_clockevent_init(void);
return smtc_clockevent_init(); return smtc_clockevent_init();
#elif defined(CONFIG_CEVT_GIC)
return (gic_clockevent_init() | r4k_clockevent_init());
#elif defined(CONFIG_CEVT_R4K) #elif defined(CONFIG_CEVT_R4K)
return r4k_clockevent_init(); return r4k_clockevent_init();
#else #else
...@@ -69,9 +71,7 @@ static inline int mips_clockevent_init(void) ...@@ -69,9 +71,7 @@ static inline int mips_clockevent_init(void)
/* /*
* Initialize the count register as a clocksource * Initialize the count register as a clocksource
*/ */
#ifdef CONFIG_CSRC_R4K
extern int init_r4k_clocksource(void); extern int init_r4k_clocksource(void);
#endif
static inline int init_mips_clocksource(void) static inline int init_mips_clocksource(void)
{ {
......
...@@ -270,6 +270,7 @@ do { \ ...@@ -270,6 +270,7 @@ do { \
__asm__ __volatile__( \ __asm__ __volatile__( \
"1: " insn " %1, %3 \n" \ "1: " insn " %1, %3 \n" \
"2: \n" \ "2: \n" \
" .insn \n" \
" .section .fixup,\"ax\" \n" \ " .section .fixup,\"ax\" \n" \
"3: li %0, %4 \n" \ "3: li %0, %4 \n" \
" j 2b \n" \ " j 2b \n" \
...@@ -296,7 +297,9 @@ do { \ ...@@ -296,7 +297,9 @@ do { \
__asm__ __volatile__( \ __asm__ __volatile__( \
"1: lw %1, (%3) \n" \ "1: lw %1, (%3) \n" \
"2: lw %D1, 4(%3) \n" \ "2: lw %D1, 4(%3) \n" \
"3: .section .fixup,\"ax\" \n" \ "3: \n" \
" .insn \n" \
" .section .fixup,\"ax\" \n" \
"4: li %0, %4 \n" \ "4: li %0, %4 \n" \
" move %1, $0 \n" \ " move %1, $0 \n" \
" move %D1, $0 \n" \ " move %D1, $0 \n" \
...@@ -364,6 +367,7 @@ do { \ ...@@ -364,6 +367,7 @@ do { \
__asm__ __volatile__( \ __asm__ __volatile__( \
"1: " insn " %z2, %3 # __put_user_asm\n" \ "1: " insn " %z2, %3 # __put_user_asm\n" \
"2: \n" \ "2: \n" \
" .insn \n" \
" .section .fixup,\"ax\" \n" \ " .section .fixup,\"ax\" \n" \
"3: li %0, %4 \n" \ "3: li %0, %4 \n" \
" j 2b \n" \ " j 2b \n" \
...@@ -382,6 +386,7 @@ do { \ ...@@ -382,6 +386,7 @@ do { \
"1: sw %2, (%3) # __put_user_asm_ll32 \n" \ "1: sw %2, (%3) # __put_user_asm_ll32 \n" \
"2: sw %D2, 4(%3) \n" \ "2: sw %D2, 4(%3) \n" \
"3: \n" \ "3: \n" \
" .insn \n" \
" .section .fixup,\"ax\" \n" \ " .section .fixup,\"ax\" \n" \
"4: li %0, %4 \n" \ "4: li %0, %4 \n" \
" j 3b \n" \ " j 3b \n" \
...@@ -533,6 +538,7 @@ do { \ ...@@ -533,6 +538,7 @@ do { \
__asm__ __volatile__( \ __asm__ __volatile__( \
"1: " insn " %1, %3 \n" \ "1: " insn " %1, %3 \n" \
"2: \n" \ "2: \n" \
" .insn \n" \
" .section .fixup,\"ax\" \n" \ " .section .fixup,\"ax\" \n" \
"3: li %0, %4 \n" \ "3: li %0, %4 \n" \
" j 2b \n" \ " j 2b \n" \
...@@ -558,7 +564,9 @@ do { \ ...@@ -558,7 +564,9 @@ do { \
"1: ulw %1, (%3) \n" \ "1: ulw %1, (%3) \n" \
"2: ulw %D1, 4(%3) \n" \ "2: ulw %D1, 4(%3) \n" \
" move %0, $0 \n" \ " move %0, $0 \n" \
"3: .section .fixup,\"ax\" \n" \ "3: \n" \
" .insn \n" \
" .section .fixup,\"ax\" \n" \
"4: li %0, %4 \n" \ "4: li %0, %4 \n" \
" move %1, $0 \n" \ " move %1, $0 \n" \
" move %D1, $0 \n" \ " move %D1, $0 \n" \
...@@ -625,6 +633,7 @@ do { \ ...@@ -625,6 +633,7 @@ do { \
__asm__ __volatile__( \ __asm__ __volatile__( \
"1: " insn " %z2, %3 # __put_user_unaligned_asm\n" \ "1: " insn " %z2, %3 # __put_user_unaligned_asm\n" \
"2: \n" \ "2: \n" \
" .insn \n" \
" .section .fixup,\"ax\" \n" \ " .section .fixup,\"ax\" \n" \
"3: li %0, %4 \n" \ "3: li %0, %4 \n" \
" j 2b \n" \ " j 2b \n" \
...@@ -643,6 +652,7 @@ do { \ ...@@ -643,6 +652,7 @@ do { \
"1: sw %2, (%3) # __put_user_unaligned_asm_ll32 \n" \ "1: sw %2, (%3) # __put_user_unaligned_asm_ll32 \n" \
"2: sw %D2, 4(%3) \n" \ "2: sw %D2, 4(%3) \n" \
"3: \n" \ "3: \n" \
" .insn \n" \
" .section .fixup,\"ax\" \n" \ " .section .fixup,\"ax\" \n" \
"4: li %0, %4 \n" \ "4: li %0, %4 \n" \
" j 3b \n" \ " j 3b \n" \
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Copyright (C) 2004, 2005, 2006, 2008 Thiemo Seufer * Copyright (C) 2004, 2005, 2006, 2008 Thiemo Seufer
* Copyright (C) 2005 Maciej W. Rozycki * Copyright (C) 2005 Maciej W. Rozycki
* Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org) * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
* Copyright (C) 2012 MIPS Technologies, Inc. * Copyright (C) 2012, 2013 MIPS Technologies, Inc. All rights reserved.
*/ */
#include <linux/types.h> #include <linux/types.h>
...@@ -22,44 +22,75 @@ ...@@ -22,44 +22,75 @@
#define UASM_EXPORT_SYMBOL(sym) #define UASM_EXPORT_SYMBOL(sym)
#endif #endif
#define _UASM_ISA_CLASSIC 0
#define _UASM_ISA_MICROMIPS 1
#ifndef UASM_ISA
#ifdef CONFIG_CPU_MICROMIPS
#define UASM_ISA _UASM_ISA_MICROMIPS
#else
#define UASM_ISA _UASM_ISA_CLASSIC
#endif
#endif
#if (UASM_ISA == _UASM_ISA_CLASSIC)
#ifdef CONFIG_CPU_MICROMIPS
#define ISAOPC(op) CL_uasm_i##op
#define ISAFUNC(x) CL_##x
#else
#define ISAOPC(op) uasm_i##op
#define ISAFUNC(x) x
#endif
#elif (UASM_ISA == _UASM_ISA_MICROMIPS)
#ifdef CONFIG_CPU_MICROMIPS
#define ISAOPC(op) uasm_i##op
#define ISAFUNC(x) x
#else
#define ISAOPC(op) MM_uasm_i##op
#define ISAFUNC(x) MM_##x
#endif
#else
#error Unsupported micro-assembler ISA!!!
#endif
#define Ip_u1u2u3(op) \ #define Ip_u1u2u3(op) \
void __uasminit \ void __uasminit \
uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c) ISAOPC(op)(u32 **buf, unsigned int a, unsigned int b, unsigned int c)
#define Ip_u2u1u3(op) \ #define Ip_u2u1u3(op) \
void __uasminit \ void __uasminit \
uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c) ISAOPC(op)(u32 **buf, unsigned int a, unsigned int b, unsigned int c)
#define Ip_u3u1u2(op) \ #define Ip_u3u1u2(op) \
void __uasminit \ void __uasminit \
uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c) ISAOPC(op)(u32 **buf, unsigned int a, unsigned int b, unsigned int c)
#define Ip_u1u2s3(op) \ #define Ip_u1u2s3(op) \
void __uasminit \ void __uasminit \
uasm_i##op(u32 **buf, unsigned int a, unsigned int b, signed int c) ISAOPC(op)(u32 **buf, unsigned int a, unsigned int b, signed int c)
#define Ip_u2s3u1(op) \ #define Ip_u2s3u1(op) \
void __uasminit \ void __uasminit \
uasm_i##op(u32 **buf, unsigned int a, signed int b, unsigned int c) ISAOPC(op)(u32 **buf, unsigned int a, signed int b, unsigned int c)
#define Ip_u2u1s3(op) \ #define Ip_u2u1s3(op) \
void __uasminit \ void __uasminit \
uasm_i##op(u32 **buf, unsigned int a, unsigned int b, signed int c) ISAOPC(op)(u32 **buf, unsigned int a, unsigned int b, signed int c)
#define Ip_u2u1msbu3(op) \ #define Ip_u2u1msbu3(op) \
void __uasminit \ void __uasminit \
uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c, \ ISAOPC(op)(u32 **buf, unsigned int a, unsigned int b, unsigned int c, \
unsigned int d) unsigned int d)
#define Ip_u1u2(op) \ #define Ip_u1u2(op) \
void __uasminit uasm_i##op(u32 **buf, unsigned int a, unsigned int b) void __uasminit ISAOPC(op)(u32 **buf, unsigned int a, unsigned int b)
#define Ip_u1s2(op) \ #define Ip_u1s2(op) \
void __uasminit uasm_i##op(u32 **buf, unsigned int a, signed int b) void __uasminit ISAOPC(op)(u32 **buf, unsigned int a, signed int b)
#define Ip_u1(op) void __uasminit uasm_i##op(u32 **buf, unsigned int a) #define Ip_u1(op) void __uasminit ISAOPC(op)(u32 **buf, unsigned int a)
#define Ip_0(op) void __uasminit uasm_i##op(u32 **buf) #define Ip_0(op) void __uasminit ISAOPC(op)(u32 **buf)
Ip_u2u1s3(_addiu); Ip_u2u1s3(_addiu);
Ip_u3u1u2(_addu); Ip_u3u1u2(_addu);
...@@ -132,19 +163,20 @@ struct uasm_label { ...@@ -132,19 +163,20 @@ struct uasm_label {
int lab; int lab;
}; };
void __uasminit uasm_build_label(struct uasm_label **lab, u32 *addr, int lid); void __uasminit ISAFUNC(uasm_build_label)(struct uasm_label **lab, u32 *addr,
int lid);
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
int uasm_in_compat_space_p(long addr); int ISAFUNC(uasm_in_compat_space_p)(long addr);
#endif #endif
int uasm_rel_hi(long val); int ISAFUNC(uasm_rel_hi)(long val);
int uasm_rel_lo(long val); int ISAFUNC(uasm_rel_lo)(long val);
void UASM_i_LA_mostly(u32 **buf, unsigned int rs, long addr); void ISAFUNC(UASM_i_LA_mostly)(u32 **buf, unsigned int rs, long addr);
void UASM_i_LA(u32 **buf, unsigned int rs, long addr); void ISAFUNC(UASM_i_LA)(u32 **buf, unsigned int rs, long addr);
#define UASM_L_LA(lb) \ #define UASM_L_LA(lb) \
static inline void __uasminit uasm_l##lb(struct uasm_label **lab, u32 *addr) \ static inline void __uasminit ISAFUNC(uasm_l##lb)(struct uasm_label **lab, u32 *addr) \
{ \ { \
uasm_build_label(lab, addr, label##lb); \ ISAFUNC(uasm_build_label)(lab, addr, label##lb); \
} }
/* convenience macros for instructions */ /* convenience macros for instructions */
...@@ -196,27 +228,27 @@ static inline void uasm_i_drotr_safe(u32 **p, unsigned int a1, ...@@ -196,27 +228,27 @@ static inline void uasm_i_drotr_safe(u32 **p, unsigned int a1,
unsigned int a2, unsigned int a3) unsigned int a2, unsigned int a3)
{ {
if (a3 < 32) if (a3 < 32)
uasm_i_drotr(p, a1, a2, a3); ISAOPC(_drotr)(p, a1, a2, a3);
else else
uasm_i_drotr32(p, a1, a2, a3 - 32); ISAOPC(_drotr32)(p, a1, a2, a3 - 32);
} }
static inline void uasm_i_dsll_safe(u32 **p, unsigned int a1, static inline void uasm_i_dsll_safe(u32 **p, unsigned int a1,
unsigned int a2, unsigned int a3) unsigned int a2, unsigned int a3)
{ {
if (a3 < 32) if (a3 < 32)
uasm_i_dsll(p, a1, a2, a3); ISAOPC(_dsll)(p, a1, a2, a3);
else else
uasm_i_dsll32(p, a1, a2, a3 - 32); ISAOPC(_dsll32)(p, a1, a2, a3 - 32);
} }
static inline void uasm_i_dsrl_safe(u32 **p, unsigned int a1, static inline void uasm_i_dsrl_safe(u32 **p, unsigned int a1,
unsigned int a2, unsigned int a3) unsigned int a2, unsigned int a3)
{ {
if (a3 < 32) if (a3 < 32)
uasm_i_dsrl(p, a1, a2, a3); ISAOPC(_dsrl)(p, a1, a2, a3);
else else
uasm_i_dsrl32(p, a1, a2, a3 - 32); ISAOPC(_dsrl32)(p, a1, a2, a3 - 32);
} }
/* Handle relocations. */ /* Handle relocations. */
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* *
* Copyright (C) 1996, 2000 by Ralf Baechle * Copyright (C) 1996, 2000 by Ralf Baechle
* Copyright (C) 2006 by Thiemo Seufer * Copyright (C) 2006 by Thiemo Seufer
* Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
*/ */
#ifndef _UAPI_ASM_INST_H #ifndef _UAPI_ASM_INST_H
#define _UAPI_ASM_INST_H #define _UAPI_ASM_INST_H
...@@ -192,6 +193,282 @@ enum lx_func { ...@@ -192,6 +193,282 @@ enum lx_func {
lbx_op = 0x16, lbx_op = 0x16,
}; };
/*
* (microMIPS) Major opcodes.
*/
enum mm_major_op {
mm_pool32a_op, mm_pool16a_op, mm_lbu16_op, mm_move16_op,
mm_addi32_op, mm_lbu32_op, mm_sb32_op, mm_lb32_op,
mm_pool32b_op, mm_pool16b_op, mm_lhu16_op, mm_andi16_op,
mm_addiu32_op, mm_lhu32_op, mm_sh32_op, mm_lh32_op,
mm_pool32i_op, mm_pool16c_op, mm_lwsp16_op, mm_pool16d_op,
mm_ori32_op, mm_pool32f_op, mm_reserved1_op, mm_reserved2_op,
mm_pool32c_op, mm_lwgp16_op, mm_lw16_op, mm_pool16e_op,
mm_xori32_op, mm_jals32_op, mm_addiupc_op, mm_reserved3_op,
mm_reserved4_op, mm_pool16f_op, mm_sb16_op, mm_beqz16_op,
mm_slti32_op, mm_beq32_op, mm_swc132_op, mm_lwc132_op,
mm_reserved5_op, mm_reserved6_op, mm_sh16_op, mm_bnez16_op,
mm_sltiu32_op, mm_bne32_op, mm_sdc132_op, mm_ldc132_op,
mm_reserved7_op, mm_reserved8_op, mm_swsp16_op, mm_b16_op,
mm_andi32_op, mm_j32_op, mm_sd32_op, mm_ld32_op,
mm_reserved11_op, mm_reserved12_op, mm_sw16_op, mm_li16_op,
mm_jalx32_op, mm_jal32_op, mm_sw32_op, mm_lw32_op,
};
/*
* (microMIPS) POOL32I minor opcodes.
*/
enum mm_32i_minor_op {
mm_bltz_op, mm_bltzal_op, mm_bgez_op, mm_bgezal_op,
mm_blez_op, mm_bnezc_op, mm_bgtz_op, mm_beqzc_op,
mm_tlti_op, mm_tgei_op, mm_tltiu_op, mm_tgeiu_op,
mm_tnei_op, mm_lui_op, mm_teqi_op, mm_reserved13_op,
mm_synci_op, mm_bltzals_op, mm_reserved14_op, mm_bgezals_op,
mm_bc2f_op, mm_bc2t_op, mm_reserved15_op, mm_reserved16_op,
mm_reserved17_op, mm_reserved18_op, mm_bposge64_op, mm_bposge32_op,
mm_bc1f_op, mm_bc1t_op, mm_reserved19_op, mm_reserved20_op,
mm_bc1any2f_op, mm_bc1any2t_op, mm_bc1any4f_op, mm_bc1any4t_op,
};
/*
* (microMIPS) POOL32A minor opcodes.
*/
enum mm_32a_minor_op {
mm_sll32_op = 0x000,
mm_ins_op = 0x00c,
mm_ext_op = 0x02c,
mm_pool32axf_op = 0x03c,
mm_srl32_op = 0x040,
mm_sra_op = 0x080,
mm_rotr_op = 0x0c0,
mm_lwxs_op = 0x118,
mm_addu32_op = 0x150,
mm_subu32_op = 0x1d0,
mm_and_op = 0x250,
mm_or32_op = 0x290,
mm_xor32_op = 0x310,
};
/*
* (microMIPS) POOL32B functions.
*/
enum mm_32b_func {
mm_lwc2_func = 0x0,
mm_lwp_func = 0x1,
mm_ldc2_func = 0x2,
mm_ldp_func = 0x4,
mm_lwm32_func = 0x5,
mm_cache_func = 0x6,
mm_ldm_func = 0x7,
mm_swc2_func = 0x8,
mm_swp_func = 0x9,
mm_sdc2_func = 0xa,
mm_sdp_func = 0xc,
mm_swm32_func = 0xd,
mm_sdm_func = 0xf,
};
/*
* (microMIPS) POOL32C functions.
*/
enum mm_32c_func {
mm_pref_func = 0x2,
mm_ll_func = 0x3,
mm_swr_func = 0x9,
mm_sc_func = 0xb,
mm_lwu_func = 0xe,
};
/*
* (microMIPS) POOL32AXF minor opcodes.
*/
enum mm_32axf_minor_op {
mm_mfc0_op = 0x003,
mm_mtc0_op = 0x00b,
mm_tlbp_op = 0x00d,
mm_jalr_op = 0x03c,
mm_tlbr_op = 0x04d,
mm_jalrhb_op = 0x07c,
mm_tlbwi_op = 0x08d,
mm_tlbwr_op = 0x0cd,
mm_jalrs_op = 0x13c,
mm_jalrshb_op = 0x17c,
mm_syscall_op = 0x22d,
mm_eret_op = 0x3cd,
};
/*
* (microMIPS) POOL32F minor opcodes.
*/
enum mm_32f_minor_op {
mm_32f_00_op = 0x00,
mm_32f_01_op = 0x01,
mm_32f_02_op = 0x02,
mm_32f_10_op = 0x08,
mm_32f_11_op = 0x09,
mm_32f_12_op = 0x0a,
mm_32f_20_op = 0x10,
mm_32f_30_op = 0x18,
mm_32f_40_op = 0x20,
mm_32f_41_op = 0x21,
mm_32f_42_op = 0x22,
mm_32f_50_op = 0x28,
mm_32f_51_op = 0x29,
mm_32f_52_op = 0x2a,
mm_32f_60_op = 0x30,
mm_32f_70_op = 0x38,
mm_32f_73_op = 0x3b,
mm_32f_74_op = 0x3c,
};
/*
* (microMIPS) POOL32F secondary minor opcodes.
*/
enum mm_32f_10_minor_op {
mm_lwxc1_op = 0x1,
mm_swxc1_op,
mm_ldxc1_op,
mm_sdxc1_op,
mm_luxc1_op,
mm_suxc1_op,
};
enum mm_32f_func {
mm_lwxc1_func = 0x048,
mm_swxc1_func = 0x088,
mm_ldxc1_func = 0x0c8,
mm_sdxc1_func = 0x108,
};
/*
* (microMIPS) POOL32F secondary minor opcodes.
*/
enum mm_32f_40_minor_op {
mm_fmovf_op,
mm_fmovt_op,
};
/*
* (microMIPS) POOL32F secondary minor opcodes.
*/
enum mm_32f_60_minor_op {
mm_fadd_op,
mm_fsub_op,
mm_fmul_op,
mm_fdiv_op,
};
/*
* (microMIPS) POOL32F secondary minor opcodes.
*/
enum mm_32f_70_minor_op {
mm_fmovn_op,
mm_fmovz_op,
};
/*
* (microMIPS) POOL32FXF secondary minor opcodes for POOL32F.
*/
enum mm_32f_73_minor_op {
mm_fmov0_op = 0x01,
mm_fcvtl_op = 0x04,
mm_movf0_op = 0x05,
mm_frsqrt_op = 0x08,
mm_ffloorl_op = 0x0c,
mm_fabs0_op = 0x0d,
mm_fcvtw_op = 0x24,
mm_movt0_op = 0x25,
mm_fsqrt_op = 0x28,
mm_ffloorw_op = 0x2c,
mm_fneg0_op = 0x2d,
mm_cfc1_op = 0x40,
mm_frecip_op = 0x48,
mm_fceill_op = 0x4c,
mm_fcvtd0_op = 0x4d,
mm_ctc1_op = 0x60,
mm_fceilw_op = 0x6c,
mm_fcvts0_op = 0x6d,
mm_mfc1_op = 0x80,
mm_fmov1_op = 0x81,
mm_movf1_op = 0x85,
mm_ftruncl_op = 0x8c,
mm_fabs1_op = 0x8d,
mm_mtc1_op = 0xa0,
mm_movt1_op = 0xa5,
mm_ftruncw_op = 0xac,
mm_fneg1_op = 0xad,
mm_froundl_op = 0xcc,
mm_fcvtd1_op = 0xcd,
mm_froundw_op = 0xec,
mm_fcvts1_op = 0xed,
};
/*
* (microMIPS) POOL16C minor opcodes.
*/
enum mm_16c_minor_op {
mm_lwm16_op = 0x04,
mm_swm16_op = 0x05,
mm_jr16_op = 0x18,
mm_jrc_op = 0x1a,
mm_jalr16_op = 0x1c,
mm_jalrs16_op = 0x1e,
};
/*
* (microMIPS) POOL16D minor opcodes.
*/
enum mm_16d_minor_op {
mm_addius5_func,
mm_addiusp_func,
};
/*
* (MIPS16e) opcodes.
*/
enum MIPS16e_ops {
MIPS16e_jal_op = 003,
MIPS16e_ld_op = 007,
MIPS16e_i8_op = 014,
MIPS16e_sd_op = 017,
MIPS16e_lb_op = 020,
MIPS16e_lh_op = 021,
MIPS16e_lwsp_op = 022,
MIPS16e_lw_op = 023,
MIPS16e_lbu_op = 024,
MIPS16e_lhu_op = 025,
MIPS16e_lwpc_op = 026,
MIPS16e_lwu_op = 027,
MIPS16e_sb_op = 030,
MIPS16e_sh_op = 031,
MIPS16e_swsp_op = 032,
MIPS16e_sw_op = 033,
MIPS16e_rr_op = 035,
MIPS16e_extend_op = 036,
MIPS16e_i64_op = 037,
};
enum MIPS16e_i64_func {
MIPS16e_ldsp_func,
MIPS16e_sdsp_func,
MIPS16e_sdrasp_func,
MIPS16e_dadjsp_func,
MIPS16e_ldpc_func,
};
enum MIPS16e_rr_func {
MIPS16e_jr_func,
};
enum MIPS6e_i8_func {
MIPS16e_swrasp_func = 02,
};
/*
* (microMIPS & MIPS16e) NOP instruction.
*/
#define MM_NOP16 0x0c00
/* /*
* Damn ... bitfields depend from byteorder :-( * Damn ... bitfields depend from byteorder :-(
*/ */
...@@ -311,6 +588,262 @@ struct v_format { /* MDMX vector format */ ...@@ -311,6 +588,262 @@ struct v_format { /* MDMX vector format */
;))))))) ;)))))))
}; };
/*
* microMIPS instruction formats (32-bit length)
*
* NOTE:
* Parenthesis denote whether the format is a microMIPS instruction or
* if it is MIPS32 instruction re-encoded for use in the microMIPS ASE.
*/
struct fb_format { /* FPU branch format (MIPS32) */
BITFIELD_FIELD(unsigned int opcode : 6,
BITFIELD_FIELD(unsigned int bc : 5,
BITFIELD_FIELD(unsigned int cc : 3,
BITFIELD_FIELD(unsigned int flag : 2,
BITFIELD_FIELD(signed int simmediate : 16,
;)))))
};
struct fp0_format { /* FPU multiply and add format (MIPS32) */
BITFIELD_FIELD(unsigned int opcode : 6,
BITFIELD_FIELD(unsigned int fmt : 5,
BITFIELD_FIELD(unsigned int ft : 5,
BITFIELD_FIELD(unsigned int fs : 5,
BITFIELD_FIELD(unsigned int fd : 5,
BITFIELD_FIELD(unsigned int func : 6,
;))))))
};
struct mm_fp0_format { /* FPU multipy and add format (microMIPS) */
BITFIELD_FIELD(unsigned int opcode : 6,
BITFIELD_FIELD(unsigned int ft : 5,
BITFIELD_FIELD(unsigned int fs : 5,
BITFIELD_FIELD(unsigned int fd : 5,
BITFIELD_FIELD(unsigned int fmt : 3,
BITFIELD_FIELD(unsigned int op : 2,
BITFIELD_FIELD(unsigned int func : 6,
;)))))))
};
struct fp1_format { /* FPU mfc1 and cfc1 format (MIPS32) */
BITFIELD_FIELD(unsigned int opcode : 6,
BITFIELD_FIELD(unsigned int op : 5,
BITFIELD_FIELD(unsigned int rt : 5,
BITFIELD_FIELD(unsigned int fs : 5,
BITFIELD_FIELD(unsigned int fd : 5,
BITFIELD_FIELD(unsigned int func : 6,
;))))))
};
struct mm_fp1_format { /* FPU mfc1 and cfc1 format (microMIPS) */
BITFIELD_FIELD(unsigned int opcode : 6,
BITFIELD_FIELD(unsigned int rt : 5,
BITFIELD_FIELD(unsigned int fs : 5,
BITFIELD_FIELD(unsigned int fmt : 2,
BITFIELD_FIELD(unsigned int op : 8,
BITFIELD_FIELD(unsigned int func : 6,
;))))))
};
struct mm_fp2_format { /* FPU movt and movf format (microMIPS) */
BITFIELD_FIELD(unsigned int opcode : 6,
BITFIELD_FIELD(unsigned int fd : 5,
BITFIELD_FIELD(unsigned int fs : 5,
BITFIELD_FIELD(unsigned int cc : 3,
BITFIELD_FIELD(unsigned int zero : 2,
BITFIELD_FIELD(unsigned int fmt : 2,
BITFIELD_FIELD(unsigned int op : 3,
BITFIELD_FIELD(unsigned int func : 6,
;))))))))
};
struct mm_fp3_format { /* FPU abs and neg format (microMIPS) */
BITFIELD_FIELD(unsigned int opcode : 6,
BITFIELD_FIELD(unsigned int rt : 5,
BITFIELD_FIELD(unsigned int fs : 5,
BITFIELD_FIELD(unsigned int fmt : 3,
BITFIELD_FIELD(unsigned int op : 7,
BITFIELD_FIELD(unsigned int func : 6,
;))))))
};
struct mm_fp4_format { /* FPU c.cond format (microMIPS) */
BITFIELD_FIELD(unsigned int opcode : 6,
BITFIELD_FIELD(unsigned int rt : 5,
BITFIELD_FIELD(unsigned int fs : 5,
BITFIELD_FIELD(unsigned int cc : 3,
BITFIELD_FIELD(unsigned int fmt : 3,
BITFIELD_FIELD(unsigned int cond : 4,
BITFIELD_FIELD(unsigned int func : 6,
;)))))))
};
struct mm_fp5_format { /* FPU lwxc1 and swxc1 format (microMIPS) */
BITFIELD_FIELD(unsigned int opcode : 6,
BITFIELD_FIELD(unsigned int index : 5,
BITFIELD_FIELD(unsigned int base : 5,
BITFIELD_FIELD(unsigned int fd : 5,
BITFIELD_FIELD(unsigned int op : 5,
BITFIELD_FIELD(unsigned int func : 6,
;))))))
};
struct fp6_format { /* FPU madd and msub format (MIPS IV) */
BITFIELD_FIELD(unsigned int opcode : 6,
BITFIELD_FIELD(unsigned int fr : 5,
BITFIELD_FIELD(unsigned int ft : 5,
BITFIELD_FIELD(unsigned int fs : 5,
BITFIELD_FIELD(unsigned int fd : 5,
BITFIELD_FIELD(unsigned int func : 6,
;))))))
};
struct mm_fp6_format { /* FPU madd and msub format (microMIPS) */
BITFIELD_FIELD(unsigned int opcode : 6,
BITFIELD_FIELD(unsigned int ft : 5,
BITFIELD_FIELD(unsigned int fs : 5,
BITFIELD_FIELD(unsigned int fd : 5,
BITFIELD_FIELD(unsigned int fr : 5,
BITFIELD_FIELD(unsigned int func : 6,
;))))))
};
struct mm_i_format { /* Immediate format (microMIPS) */
BITFIELD_FIELD(unsigned int opcode : 6,
BITFIELD_FIELD(unsigned int rt : 5,
BITFIELD_FIELD(unsigned int rs : 5,
BITFIELD_FIELD(signed int simmediate : 16,
;))))
};
struct mm_m_format { /* Multi-word load/store format (microMIPS) */
BITFIELD_FIELD(unsigned int opcode : 6,
BITFIELD_FIELD(unsigned int rd : 5,
BITFIELD_FIELD(unsigned int base : 5,
BITFIELD_FIELD(unsigned int func : 4,
BITFIELD_FIELD(signed int simmediate : 12,
;)))))
};
struct mm_x_format { /* Scaled indexed load format (microMIPS) */
BITFIELD_FIELD(unsigned int opcode : 6,
BITFIELD_FIELD(unsigned int index : 5,
BITFIELD_FIELD(unsigned int base : 5,
BITFIELD_FIELD(unsigned int rd : 5,
BITFIELD_FIELD(unsigned int func : 11,
;)))))
};
/*
* microMIPS instruction formats (16-bit length)
*/
struct mm_b0_format { /* Unconditional branch format (microMIPS) */
BITFIELD_FIELD(unsigned int opcode : 6,
BITFIELD_FIELD(signed int simmediate : 10,
BITFIELD_FIELD(unsigned int : 16, /* Ignored */
;)))
};
struct mm_b1_format { /* Conditional branch format (microMIPS) */
BITFIELD_FIELD(unsigned int opcode : 6,
BITFIELD_FIELD(unsigned int rs : 3,
BITFIELD_FIELD(signed int simmediate : 7,
BITFIELD_FIELD(unsigned int : 16, /* Ignored */
;))))
};
struct mm16_m_format { /* Multi-word load/store format */
BITFIELD_FIELD(unsigned int opcode : 6,
BITFIELD_FIELD(unsigned int func : 4,
BITFIELD_FIELD(unsigned int rlist : 2,
BITFIELD_FIELD(unsigned int imm : 4,
BITFIELD_FIELD(unsigned int : 16, /* Ignored */
;)))))
};
struct mm16_rb_format { /* Signed immediate format */
BITFIELD_FIELD(unsigned int opcode : 6,
BITFIELD_FIELD(unsigned int rt : 3,
BITFIELD_FIELD(unsigned int base : 3,
BITFIELD_FIELD(signed int simmediate : 4,
BITFIELD_FIELD(unsigned int : 16, /* Ignored */
;)))))
};
struct mm16_r3_format { /* Load from global pointer format */
BITFIELD_FIELD(unsigned int opcode : 6,
BITFIELD_FIELD(unsigned int rt : 3,
BITFIELD_FIELD(signed int simmediate : 7,
BITFIELD_FIELD(unsigned int : 16, /* Ignored */
;))))
};
struct mm16_r5_format { /* Load/store from stack pointer format */
BITFIELD_FIELD(unsigned int opcode : 6,
BITFIELD_FIELD(unsigned int rt : 5,
BITFIELD_FIELD(signed int simmediate : 5,
BITFIELD_FIELD(unsigned int : 16, /* Ignored */
;))))
};
/*
* MIPS16e instruction formats (16-bit length)
*/
struct m16e_rr {
BITFIELD_FIELD(unsigned int opcode : 5,
BITFIELD_FIELD(unsigned int rx : 3,
BITFIELD_FIELD(unsigned int nd : 1,
BITFIELD_FIELD(unsigned int l : 1,
BITFIELD_FIELD(unsigned int ra : 1,
BITFIELD_FIELD(unsigned int func : 5,
;))))))
};
struct m16e_jal {
BITFIELD_FIELD(unsigned int opcode : 5,
BITFIELD_FIELD(unsigned int x : 1,
BITFIELD_FIELD(unsigned int imm20_16 : 5,
BITFIELD_FIELD(signed int imm25_21 : 5,
;))))
};
struct m16e_i64 {
BITFIELD_FIELD(unsigned int opcode : 5,
BITFIELD_FIELD(unsigned int func : 3,
BITFIELD_FIELD(unsigned int imm : 8,
;)))
};
struct m16e_ri64 {
BITFIELD_FIELD(unsigned int opcode : 5,
BITFIELD_FIELD(unsigned int func : 3,
BITFIELD_FIELD(unsigned int ry : 3,
BITFIELD_FIELD(unsigned int imm : 5,
;))))
};
struct m16e_ri {
BITFIELD_FIELD(unsigned int opcode : 5,
BITFIELD_FIELD(unsigned int rx : 3,
BITFIELD_FIELD(unsigned int imm : 8,
;)))
};
struct m16e_rri {
BITFIELD_FIELD(unsigned int opcode : 5,
BITFIELD_FIELD(unsigned int rx : 3,
BITFIELD_FIELD(unsigned int ry : 3,
BITFIELD_FIELD(unsigned int imm : 5,
;))))
};
struct m16e_i8 {
BITFIELD_FIELD(unsigned int opcode : 5,
BITFIELD_FIELD(unsigned int func : 3,
BITFIELD_FIELD(unsigned int imm : 8,
;)))
};
union mips_instruction { union mips_instruction {
unsigned int word; unsigned int word;
unsigned short halfword[2]; unsigned short halfword[2];
...@@ -326,6 +859,37 @@ union mips_instruction { ...@@ -326,6 +859,37 @@ union mips_instruction {
struct b_format b_format; struct b_format b_format;
struct ps_format ps_format; struct ps_format ps_format;
struct v_format v_format; struct v_format v_format;
struct fb_format fb_format;
struct fp0_format fp0_format;
struct mm_fp0_format mm_fp0_format;
struct fp1_format fp1_format;
struct mm_fp1_format mm_fp1_format;
struct mm_fp2_format mm_fp2_format;
struct mm_fp3_format mm_fp3_format;
struct mm_fp4_format mm_fp4_format;
struct mm_fp5_format mm_fp5_format;
struct fp6_format fp6_format;
struct mm_fp6_format mm_fp6_format;
struct mm_i_format mm_i_format;
struct mm_m_format mm_m_format;
struct mm_x_format mm_x_format;
struct mm_b0_format mm_b0_format;
struct mm_b1_format mm_b1_format;
struct mm16_m_format mm16_m_format ;
struct mm16_rb_format mm16_rb_format;
struct mm16_r3_format mm16_r3_format;
struct mm16_r5_format mm16_r5_format;
};
union mips16e_instruction {
unsigned int full : 16;
struct m16e_rr rr;
struct m16e_jal jal;
struct m16e_i64 i64;
struct m16e_ri64 ri64;
struct m16e_ri ri;
struct m16e_rri rri;
struct m16e_i8 i8;
}; };
#endif /* _UAPI_ASM_INST_H */ #endif /* _UAPI_ASM_INST_H */
...@@ -19,15 +19,16 @@ obj-$(CONFIG_CEVT_BCM1480) += cevt-bcm1480.o ...@@ -19,15 +19,16 @@ obj-$(CONFIG_CEVT_BCM1480) += cevt-bcm1480.o
obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o
obj-$(CONFIG_MIPS_MT_SMTC) += cevt-smtc.o obj-$(CONFIG_MIPS_MT_SMTC) += cevt-smtc.o
obj-$(CONFIG_CEVT_DS1287) += cevt-ds1287.o obj-$(CONFIG_CEVT_DS1287) += cevt-ds1287.o
obj-$(CONFIG_CEVT_GIC) += cevt-gic.o
obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o
obj-$(CONFIG_CEVT_SB1250) += cevt-sb1250.o obj-$(CONFIG_CEVT_SB1250) += cevt-sb1250.o
obj-$(CONFIG_CEVT_TXX9) += cevt-txx9.o obj-$(CONFIG_CEVT_TXX9) += cevt-txx9.o
obj-$(CONFIG_CSRC_BCM1480) += csrc-bcm1480.o obj-$(CONFIG_CSRC_BCM1480) += csrc-bcm1480.o
obj-$(CONFIG_CSRC_GIC) += csrc-gic.o
obj-$(CONFIG_CSRC_IOASIC) += csrc-ioasic.o obj-$(CONFIG_CSRC_IOASIC) += csrc-ioasic.o
obj-$(CONFIG_CSRC_POWERTV) += csrc-powertv.o obj-$(CONFIG_CSRC_POWERTV) += csrc-powertv.o
obj-$(CONFIG_CSRC_R4K) += csrc-r4k.o obj-$(CONFIG_CSRC_R4K) += csrc-r4k.o
obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o
obj-$(CONFIG_CSRC_GIC) += csrc-gic.o
obj-$(CONFIG_SYNC_R4K) += sync-r4k.o obj-$(CONFIG_SYNC_R4K) += sync-r4k.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_STACKTRACE) += stacktrace.o
......
...@@ -14,10 +14,186 @@ ...@@ -14,10 +14,186 @@
#include <asm/cpu.h> #include <asm/cpu.h>
#include <asm/cpu-features.h> #include <asm/cpu-features.h>
#include <asm/fpu.h> #include <asm/fpu.h>
#include <asm/fpu_emulator.h>
#include <asm/inst.h> #include <asm/inst.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
/*
* Calculate and return exception PC in case of branch delay slot
* for microMIPS and MIPS16e. It does not clear the ISA mode bit.
*/
int __isa_exception_epc(struct pt_regs *regs)
{
unsigned short inst;
long epc = regs->cp0_epc;
/* Calculate exception PC in branch delay slot. */
if (__get_user(inst, (u16 __user *) msk_isa16_mode(epc))) {
/* This should never happen because delay slot was checked. */
force_sig(SIGSEGV, current);
return epc;
}
if (cpu_has_mips16) {
if (((union mips16e_instruction)inst).ri.opcode
== MIPS16e_jal_op)
epc += 4;
else
epc += 2;
} else if (mm_insn_16bit(inst))
epc += 2;
else
epc += 4;
return epc;
}
/*
* Compute return address and emulate branch in microMIPS mode after an
* exception only. It does not handle compact branches/jumps and cannot
* be used in interrupt context. (Compact branches/jumps do not cause
* exceptions.)
*/
int __microMIPS_compute_return_epc(struct pt_regs *regs)
{
u16 __user *pc16;
u16 halfword;
unsigned int word;
unsigned long contpc;
struct mm_decoded_insn mminsn = { 0 };
mminsn.micro_mips_mode = 1;
/* This load never faults. */
pc16 = (unsigned short __user *)msk_isa16_mode(regs->cp0_epc);
__get_user(halfword, pc16);
pc16++;
contpc = regs->cp0_epc + 2;
word = ((unsigned int)halfword << 16);
mminsn.pc_inc = 2;
if (!mm_insn_16bit(halfword)) {
__get_user(halfword, pc16);
pc16++;
contpc = regs->cp0_epc + 4;
mminsn.pc_inc = 4;
word |= halfword;
}
mminsn.insn = word;
if (get_user(halfword, pc16))
goto sigsegv;
mminsn.next_pc_inc = 2;
word = ((unsigned int)halfword << 16);
if (!mm_insn_16bit(halfword)) {
pc16++;
if (get_user(halfword, pc16))
goto sigsegv;
mminsn.next_pc_inc = 4;
word |= halfword;
}
mminsn.next_insn = word;
mm_isBranchInstr(regs, mminsn, &contpc);
regs->cp0_epc = contpc;
return 0;
sigsegv:
force_sig(SIGSEGV, current);
return -EFAULT;
}
/*
* Compute return address and emulate branch in MIPS16e mode after an
* exception only. It does not handle compact branches/jumps and cannot
* be used in interrupt context. (Compact branches/jumps do not cause
* exceptions.)
*/
int __MIPS16e_compute_return_epc(struct pt_regs *regs)
{
u16 __user *addr;
union mips16e_instruction inst;
u16 inst2;
u32 fullinst;
long epc;
epc = regs->cp0_epc;
/* Read the instruction. */
addr = (u16 __user *)msk_isa16_mode(epc);
if (__get_user(inst.full, addr)) {
force_sig(SIGSEGV, current);
return -EFAULT;
}
switch (inst.ri.opcode) {
case MIPS16e_extend_op:
regs->cp0_epc += 4;
return 0;
/*
* JAL and JALX in MIPS16e mode
*/
case MIPS16e_jal_op:
addr += 1;
if (__get_user(inst2, addr)) {
force_sig(SIGSEGV, current);
return -EFAULT;
}
fullinst = ((unsigned)inst.full << 16) | inst2;
regs->regs[31] = epc + 6;
epc += 4;
epc >>= 28;
epc <<= 28;
/*
* JAL:5 X:1 TARGET[20-16]:5 TARGET[25:21]:5 TARGET[15:0]:16
*
* ......TARGET[15:0].................TARGET[20:16]...........
* ......TARGET[25:21]
*/
epc |=
((fullinst & 0xffff) << 2) | ((fullinst & 0x3e00000) >> 3) |
((fullinst & 0x1f0000) << 7);
if (!inst.jal.x)
set_isa16_mode(epc); /* Set ISA mode bit. */
regs->cp0_epc = epc;
return 0;
/*
* J(AL)R(C)
*/
case MIPS16e_rr_op:
if (inst.rr.func == MIPS16e_jr_func) {
if (inst.rr.ra)
regs->cp0_epc = regs->regs[31];
else
regs->cp0_epc =
regs->regs[reg16to32[inst.rr.rx]];
if (inst.rr.l) {
if (inst.rr.nd)
regs->regs[31] = epc + 2;
else
regs->regs[31] = epc + 4;
}
return 0;
}
break;
}
/*
* All other cases have no branch delay slot and are 16-bits.
* Branches do not cause an exception.
*/
regs->cp0_epc += 2;
return 0;
}
/** /**
* __compute_return_epc_for_insn - Computes the return address and do emulate * __compute_return_epc_for_insn - Computes the return address and do emulate
* branch simulation, if required. * branch simulation, if required.
...@@ -129,6 +305,8 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, ...@@ -129,6 +305,8 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
epc <<= 28; epc <<= 28;
epc |= (insn.j_format.target << 2); epc |= (insn.j_format.target << 2);
regs->cp0_epc = epc; regs->cp0_epc = epc;
if (insn.i_format.opcode == jalx_op)
set_isa16_mode(regs->cp0_epc);
break; break;
/* /*
......
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2013 Imagination Technologies Ltd.
*/
#include <linux/clockchips.h>
#include <linux/interrupt.h>
#include <linux/percpu.h>
#include <linux/smp.h>
#include <linux/irq.h>
#include <asm/time.h>
#include <asm/gic.h>
#include <asm/mips-boards/maltaint.h>
DEFINE_PER_CPU(struct clock_event_device, gic_clockevent_device);
int gic_timer_irq_installed;
static int gic_next_event(unsigned long delta, struct clock_event_device *evt)
{
u64 cnt;
int res;
cnt = gic_read_count();
cnt += (u64)delta;
gic_write_compare(cnt);
res = ((int)(gic_read_count() - cnt) >= 0) ? -ETIME : 0;
return res;
}
void gic_set_clock_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
/* Nothing to do ... */
}
irqreturn_t gic_compare_interrupt(int irq, void *dev_id)
{
struct clock_event_device *cd;
int cpu = smp_processor_id();
gic_write_compare(gic_read_compare());
cd = &per_cpu(gic_clockevent_device, cpu);
cd->event_handler(cd);
return IRQ_HANDLED;
}
struct irqaction gic_compare_irqaction = {
.handler = gic_compare_interrupt,
.flags = IRQF_PERCPU | IRQF_TIMER,
.name = "timer",
};
void gic_event_handler(struct clock_event_device *dev)
{
}
int __cpuinit gic_clockevent_init(void)
{
unsigned int cpu = smp_processor_id();
struct clock_event_device *cd;
unsigned int irq;
if (!cpu_has_counter || !gic_frequency)
return -ENXIO;
irq = MIPS_GIC_IRQ_BASE;
cd = &per_cpu(gic_clockevent_device, cpu);
cd->name = "MIPS GIC";
cd->features = CLOCK_EVT_FEAT_ONESHOT;
clockevent_set_clock(cd, gic_frequency);
/* Calculate the min / max delta */
cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
cd->rating = 300;
cd->irq = irq;
cd->cpumask = cpumask_of(cpu);
cd->set_next_event = gic_next_event;
cd->set_mode = gic_set_clock_mode;
cd->event_handler = gic_event_handler;
clockevents_register_device(cd);
GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_MAP), 0x80000002);
GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), GIC_VPE_SMASK_CMP_MSK);
if (gic_timer_irq_installed)
return 0;
gic_timer_irq_installed = 1;
setup_irq(irq, &gic_compare_irqaction);
irq_set_handler(irq, handle_percpu_irq);
return 0;
}
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
*/ */
#ifndef CONFIG_MIPS_MT_SMTC #ifndef CONFIG_MIPS_MT_SMTC
static int mips_next_event(unsigned long delta, static int mips_next_event(unsigned long delta,
struct clock_event_device *evt) struct clock_event_device *evt)
{ {
...@@ -49,7 +48,6 @@ DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device); ...@@ -49,7 +48,6 @@ DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device);
int cp0_timer_irq_installed; int cp0_timer_irq_installed;
#ifndef CONFIG_MIPS_MT_SMTC #ifndef CONFIG_MIPS_MT_SMTC
irqreturn_t c0_compare_interrupt(int irq, void *dev_id) irqreturn_t c0_compare_interrupt(int irq, void *dev_id)
{ {
const int r2 = cpu_has_mips_r2; const int r2 = cpu_has_mips_r2;
...@@ -74,6 +72,9 @@ irqreturn_t c0_compare_interrupt(int irq, void *dev_id) ...@@ -74,6 +72,9 @@ irqreturn_t c0_compare_interrupt(int irq, void *dev_id)
/* Clear Count/Compare Interrupt */ /* Clear Count/Compare Interrupt */
write_c0_compare(read_c0_compare()); write_c0_compare(read_c0_compare());
cd = &per_cpu(mips_clockevent_device, cpu); cd = &per_cpu(mips_clockevent_device, cpu);
#ifdef CONFIG_CEVT_GIC
if (!gic_present)
#endif
cd->event_handler(cd); cd->event_handler(cd);
} }
...@@ -170,7 +171,6 @@ int c0_compare_int_usable(void) ...@@ -170,7 +171,6 @@ int c0_compare_int_usable(void)
} }
#ifndef CONFIG_MIPS_MT_SMTC #ifndef CONFIG_MIPS_MT_SMTC
int __cpuinit r4k_clockevent_init(void) int __cpuinit r4k_clockevent_init(void)
{ {
unsigned int cpu = smp_processor_id(); unsigned int cpu = smp_processor_id();
...@@ -210,6 +210,9 @@ int __cpuinit r4k_clockevent_init(void) ...@@ -210,6 +210,9 @@ int __cpuinit r4k_clockevent_init(void)
cd->set_mode = mips_set_clock_mode; cd->set_mode = mips_set_clock_mode;
cd->event_handler = mips_event_handler; cd->event_handler = mips_event_handler;
#ifdef CONFIG_CEVT_GIC
if (!gic_present)
#endif
clockevents_register_device(cd); clockevents_register_device(cd);
if (cp0_timer_irq_installed) if (cp0_timer_irq_installed)
......
...@@ -470,6 +470,9 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c) ...@@ -470,6 +470,9 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c)
c->options |= MIPS_CPU_ULRI; c->options |= MIPS_CPU_ULRI;
if (config3 & MIPS_CONF3_ISA) if (config3 & MIPS_CONF3_ISA)
c->options |= MIPS_CPU_MICROMIPS; c->options |= MIPS_CPU_MICROMIPS;
#ifdef CONFIG_CPU_MICROMIPS
write_c0_config3(read_c0_config3() | MIPS_CONF3_ISA_OE);
#endif
if (config3 & MIPS_CONF3_VZ) if (config3 & MIPS_CONF3_VZ)
c->ases |= MIPS_ASE_VZ; c->ases |= MIPS_ASE_VZ;
......
...@@ -5,23 +5,14 @@ ...@@ -5,23 +5,14 @@
* *
* Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
*/ */
#include <linux/clocksource.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/time.h>
#include <asm/time.h>
#include <asm/gic.h> #include <asm/gic.h>
static cycle_t gic_hpt_read(struct clocksource *cs) static cycle_t gic_hpt_read(struct clocksource *cs)
{ {
unsigned int hi, hi2, lo; return gic_read_count();
do {
GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi);
GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), lo);
GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi2);
} while (hi2 != hi);
return (((cycle_t) hi) << 32) + lo;
} }
static struct clocksource gic_clocksource = { static struct clocksource gic_clocksource = {
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
* *
* Copyright (C) 1994 - 2000, 2001, 2003 Ralf Baechle * Copyright (C) 1994 - 2000, 2001, 2003 Ralf Baechle
* Copyright (C) 1999, 2000 Silicon Graphics, Inc. * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
* Copyright (C) 2001 MIPS Technologies, Inc.
* Copyright (C) 2002, 2007 Maciej W. Rozycki * Copyright (C) 2002, 2007 Maciej W. Rozycki
* Copyright (C) 2001, 2012 MIPS Technologies, Inc. All rights reserved.
*/ */
#include <linux/init.h> #include <linux/init.h>
...@@ -21,8 +21,10 @@ ...@@ -21,8 +21,10 @@
#include <asm/war.h> #include <asm/war.h>
#include <asm/thread_info.h> #include <asm/thread_info.h>
#ifdef CONFIG_MIPS_MT_SMTC
#define PANIC_PIC(msg) \ #define PANIC_PIC(msg) \
.set push; \ .set push; \
.set nomicromips; \
.set reorder; \ .set reorder; \
PTR_LA a0,8f; \ PTR_LA a0,8f; \
.set noat; \ .set noat; \
...@@ -31,17 +33,10 @@ ...@@ -31,17 +33,10 @@
9: b 9b; \ 9: b 9b; \
.set pop; \ .set pop; \
TEXT(msg) TEXT(msg)
#endif
__INIT __INIT
NESTED(except_vec0_generic, 0, sp)
PANIC_PIC("Exception vector 0 called")
END(except_vec0_generic)
NESTED(except_vec1_generic, 0, sp)
PANIC_PIC("Exception vector 1 called")
END(except_vec1_generic)
/* /*
* General exception vector for all other CPUs. * General exception vector for all other CPUs.
* *
...@@ -138,12 +133,19 @@ LEAF(r4k_wait) ...@@ -138,12 +133,19 @@ LEAF(r4k_wait)
nop nop
nop nop
nop nop
#ifdef CONFIG_CPU_MICROMIPS
nop
nop
nop
nop
#endif
.set mips3 .set mips3
wait wait
/* end of rollback region (the region size must be power of two) */ /* end of rollback region (the region size must be power of two) */
.set pop
1: 1:
jr ra jr ra
nop
.set pop
END(r4k_wait) END(r4k_wait)
.macro BUILD_ROLLBACK_PROLOGUE handler .macro BUILD_ROLLBACK_PROLOGUE handler
...@@ -201,7 +203,11 @@ NESTED(handle_int, PT_SIZE, sp) ...@@ -201,7 +203,11 @@ NESTED(handle_int, PT_SIZE, sp)
LONG_L s0, TI_REGS($28) LONG_L s0, TI_REGS($28)
LONG_S sp, TI_REGS($28) LONG_S sp, TI_REGS($28)
PTR_LA ra, ret_from_irq PTR_LA ra, ret_from_irq
j plat_irq_dispatch PTR_LA v0, plat_irq_dispatch
jr v0
#ifdef CONFIG_CPU_MICROMIPS
nop
#endif
END(handle_int) END(handle_int)
__INIT __INIT
...@@ -222,11 +228,14 @@ NESTED(except_vec4, 0, sp) ...@@ -222,11 +228,14 @@ NESTED(except_vec4, 0, sp)
/* /*
* EJTAG debug exception handler. * EJTAG debug exception handler.
* The EJTAG debug exception entry point is 0xbfc00480, which * The EJTAG debug exception entry point is 0xbfc00480, which
* normally is in the boot PROM, so the boot PROM must do a * normally is in the boot PROM, so the boot PROM must do an
* unconditional jump to this vector. * unconditional jump to this vector.
*/ */
NESTED(except_vec_ejtag_debug, 0, sp) NESTED(except_vec_ejtag_debug, 0, sp)
j ejtag_debug_handler j ejtag_debug_handler
#ifdef CONFIG_CPU_MICROMIPS
nop
#endif
END(except_vec_ejtag_debug) END(except_vec_ejtag_debug)
__FINIT __FINIT
...@@ -251,9 +260,10 @@ NESTED(except_vec_vi, 0, sp) ...@@ -251,9 +260,10 @@ NESTED(except_vec_vi, 0, sp)
FEXPORT(except_vec_vi_mori) FEXPORT(except_vec_vi_mori)
ori a0, $0, 0 ori a0, $0, 0
#endif /* CONFIG_MIPS_MT_SMTC */ #endif /* CONFIG_MIPS_MT_SMTC */
PTR_LA v1, except_vec_vi_handler
FEXPORT(except_vec_vi_lui) FEXPORT(except_vec_vi_lui)
lui v0, 0 /* Patched */ lui v0, 0 /* Patched */
j except_vec_vi_handler jr v1
FEXPORT(except_vec_vi_ori) FEXPORT(except_vec_vi_ori)
ori v0, 0 /* Patched */ ori v0, 0 /* Patched */
.set pop .set pop
...@@ -354,6 +364,9 @@ EXPORT(ejtag_debug_buffer) ...@@ -354,6 +364,9 @@ EXPORT(ejtag_debug_buffer)
*/ */
NESTED(except_vec_nmi, 0, sp) NESTED(except_vec_nmi, 0, sp)
j nmi_handler j nmi_handler
#ifdef CONFIG_CPU_MICROMIPS
nop
#endif
END(except_vec_nmi) END(except_vec_nmi)
__FINIT __FINIT
...@@ -480,7 +493,7 @@ NESTED(nmi_handler, PT_SIZE, sp) ...@@ -480,7 +493,7 @@ NESTED(nmi_handler, PT_SIZE, sp)
.set noreorder .set noreorder
/* check if TLB contains a entry for EPC */ /* check if TLB contains a entry for EPC */
MFC0 k1, CP0_ENTRYHI MFC0 k1, CP0_ENTRYHI
andi k1, 0xff /* ASID_MASK */ andi k1, 0xff /* ASID_MASK patched at run-time!! */
MFC0 k0, CP0_EPC MFC0 k0, CP0_EPC
PTR_SRL k0, _PAGE_SHIFT + 1 PTR_SRL k0, _PAGE_SHIFT + 1
PTR_SLL k0, _PAGE_SHIFT + 1 PTR_SLL k0, _PAGE_SHIFT + 1
...@@ -500,13 +513,35 @@ NESTED(nmi_handler, PT_SIZE, sp) ...@@ -500,13 +513,35 @@ NESTED(nmi_handler, PT_SIZE, sp)
.set push .set push
.set noat .set noat
.set noreorder .set noreorder
/* 0x7c03e83b: rdhwr v1,$29 */ /* MIPS32: 0x7c03e83b: rdhwr v1,$29 */
/* microMIPS: 0x007d6b3c: rdhwr v1,$29 */
MFC0 k1, CP0_EPC MFC0 k1, CP0_EPC
lui k0, 0x7c03 #if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_CPU_MIPS64_R2)
lw k1, (k1) and k0, k1, 1
ori k0, 0xe83b beqz k0, 1f
.set reorder xor k1, k0
lhu k0, (k1)
lhu k1, 2(k1)
ins k1, k0, 16, 16
lui k0, 0x007d
b docheck
ori k0, 0x6b3c
1:
lui k0, 0x7c03
lw k1, (k1)
ori k0, 0xe83b
#else
andi k0, k1, 1
bnez k0, handle_ri
lui k0, 0x7c03
lw k1, (k1)
ori k0, 0xe83b
#endif
.set reorder
docheck:
bne k0, k1, handle_ri /* if not ours */ bne k0, k1, handle_ri /* if not ours */
isrdhwr:
/* The insn is rdhwr. No need to check CAUSE.BD here. */ /* The insn is rdhwr. No need to check CAUSE.BD here. */
get_saved_sp /* k1 := current_thread_info */ get_saved_sp /* k1 := current_thread_info */
.set noreorder .set noreorder
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/clocksource.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/gic.h> #include <asm/gic.h>
...@@ -19,6 +20,8 @@ ...@@ -19,6 +20,8 @@
#include <linux/hardirq.h> #include <linux/hardirq.h>
#include <asm-generic/bitops/find.h> #include <asm-generic/bitops/find.h>
unsigned int gic_frequency;
unsigned int gic_present;
unsigned long _gic_base; unsigned long _gic_base;
unsigned int gic_irq_base; unsigned int gic_irq_base;
unsigned int gic_irq_flags[GIC_NUM_INTRS]; unsigned int gic_irq_flags[GIC_NUM_INTRS];
...@@ -30,6 +33,39 @@ static struct gic_pcpu_mask pcpu_masks[NR_CPUS]; ...@@ -30,6 +33,39 @@ static struct gic_pcpu_mask pcpu_masks[NR_CPUS];
static struct gic_pending_regs pending_regs[NR_CPUS]; static struct gic_pending_regs pending_regs[NR_CPUS];
static struct gic_intrmask_regs intrmask_regs[NR_CPUS]; static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
#if defined(CONFIG_CSRC_GIC) || defined(CONFIG_CEVT_GIC)
cycle_t gic_read_count(void)
{
unsigned int hi, hi2, lo;
do {
GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi);
GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), lo);
GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi2);
} while (hi2 != hi);
return (((cycle_t) hi) << 32) + lo;
}
void gic_write_compare(cycle_t cnt)
{
GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI),
(int)(cnt >> 32));
GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO),
(int)(cnt & 0xffffffff));
}
cycle_t gic_read_compare(void)
{
unsigned int hi, lo;
GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), hi);
GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), lo);
return (((cycle_t) hi) << 32) + lo;
}
#endif
unsigned int gic_get_timer_pending(void) unsigned int gic_get_timer_pending(void)
{ {
unsigned int vpe_pending; unsigned int vpe_pending;
...@@ -116,6 +152,17 @@ static void __init vpe_local_setup(unsigned int numvpes) ...@@ -116,6 +152,17 @@ static void __init vpe_local_setup(unsigned int numvpes)
} }
} }
unsigned int gic_compare_int(void)
{
unsigned int pending;
GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_PEND), pending);
if (pending & GIC_VPE_PEND_CMP_MSK)
return 1;
else
return 0;
}
unsigned int gic_get_int(void) unsigned int gic_get_int(void)
{ {
unsigned int i; unsigned int i;
......
...@@ -99,6 +99,10 @@ static int show_cpuinfo(struct seq_file *m, void *v) ...@@ -99,6 +99,10 @@ static int show_cpuinfo(struct seq_file *m, void *v)
if (cpu_has_vz) seq_printf(m, "%s", " vz"); if (cpu_has_vz) seq_printf(m, "%s", " vz");
seq_printf(m, "\n"); seq_printf(m, "\n");
if (cpu_has_mmips) {
seq_printf(m, "micromips kernel\t: %s\n",
(read_c0_config3() & MIPS_CONF3_ISA_OE) ? "yes" : "no");
}
seq_printf(m, "shadow register sets\t: %d\n", seq_printf(m, "shadow register sets\t: %d\n",
cpu_data[n].srsets); cpu_data[n].srsets);
seq_printf(m, "kscratch registers\t: %d\n", seq_printf(m, "kscratch registers\t: %d\n",
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* Copyright (C) 2005, 2006 by Ralf Baechle (ralf@linux-mips.org) * Copyright (C) 2005, 2006 by Ralf Baechle (ralf@linux-mips.org)
* Copyright (C) 1999, 2000 Silicon Graphics, Inc. * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
* Copyright (C) 2004 Thiemo Seufer * Copyright (C) 2004 Thiemo Seufer
* Copyright (C) 2013 Imagination Technologies Ltd.
*/ */
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/sched.h> #include <linux/sched.h>
...@@ -243,34 +244,115 @@ struct mips_frame_info { ...@@ -243,34 +244,115 @@ struct mips_frame_info {
static inline int is_ra_save_ins(union mips_instruction *ip) static inline int is_ra_save_ins(union mips_instruction *ip)
{ {
#ifdef CONFIG_CPU_MICROMIPS
union mips_instruction mmi;
/*
* swsp ra,offset
* swm16 reglist,offset(sp)
* swm32 reglist,offset(sp)
* sw32 ra,offset(sp)
* jradiussp - NOT SUPPORTED
*
* microMIPS is way more fun...
*/
if (mm_insn_16bit(ip->halfword[0])) {
mmi.word = (ip->halfword[0] << 16);
return ((mmi.mm16_r5_format.opcode == mm_swsp16_op &&
mmi.mm16_r5_format.rt == 31) ||
(mmi.mm16_m_format.opcode == mm_pool16c_op &&
mmi.mm16_m_format.func == mm_swm16_op));
}
else {
mmi.halfword[0] = ip->halfword[1];
mmi.halfword[1] = ip->halfword[0];
return ((mmi.mm_m_format.opcode == mm_pool32b_op &&
mmi.mm_m_format.rd > 9 &&
mmi.mm_m_format.base == 29 &&
mmi.mm_m_format.func == mm_swm32_func) ||
(mmi.i_format.opcode == mm_sw32_op &&
mmi.i_format.rs == 29 &&
mmi.i_format.rt == 31));
}
#else
/* sw / sd $ra, offset($sp) */ /* sw / sd $ra, offset($sp) */
return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) && return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) &&
ip->i_format.rs == 29 && ip->i_format.rs == 29 &&
ip->i_format.rt == 31; ip->i_format.rt == 31;
#endif
} }
static inline int is_jal_jalr_jr_ins(union mips_instruction *ip) static inline int is_jal_jalr_jr_ins(union mips_instruction *ip)
{ {
#ifdef CONFIG_CPU_MICROMIPS
/*
* jr16,jrc,jalr16,jalr16
* jal
* jalr/jr,jalr.hb/jr.hb,jalrs,jalrs.hb
* jraddiusp - NOT SUPPORTED
*
* microMIPS is kind of more fun...
*/
union mips_instruction mmi;
mmi.word = (ip->halfword[0] << 16);
if ((mmi.mm16_r5_format.opcode == mm_pool16c_op &&
(mmi.mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op) ||
ip->j_format.opcode == mm_jal32_op)
return 1;
if (ip->r_format.opcode != mm_pool32a_op ||
ip->r_format.func != mm_pool32axf_op)
return 0;
return (((ip->u_format.uimmediate >> 6) & mm_jalr_op) == mm_jalr_op);
#else
if (ip->j_format.opcode == jal_op) if (ip->j_format.opcode == jal_op)
return 1; return 1;
if (ip->r_format.opcode != spec_op) if (ip->r_format.opcode != spec_op)
return 0; return 0;
return ip->r_format.func == jalr_op || ip->r_format.func == jr_op; return ip->r_format.func == jalr_op || ip->r_format.func == jr_op;
#endif
} }
static inline int is_sp_move_ins(union mips_instruction *ip) static inline int is_sp_move_ins(union mips_instruction *ip)
{ {
#ifdef CONFIG_CPU_MICROMIPS
/*
* addiusp -imm
* addius5 sp,-imm
* addiu32 sp,sp,-imm
* jradiussp - NOT SUPPORTED
*
* microMIPS is not more fun...
*/
if (mm_insn_16bit(ip->halfword[0])) {
union mips_instruction mmi;
mmi.word = (ip->halfword[0] << 16);
return ((mmi.mm16_r3_format.opcode == mm_pool16d_op &&
mmi.mm16_r3_format.simmediate && mm_addiusp_func) ||
(mmi.mm16_r5_format.opcode == mm_pool16d_op &&
mmi.mm16_r5_format.rt == 29));
}
return (ip->mm_i_format.opcode == mm_addiu32_op &&
ip->mm_i_format.rt == 29 && ip->mm_i_format.rs == 29);
#else
/* addiu/daddiu sp,sp,-imm */ /* addiu/daddiu sp,sp,-imm */
if (ip->i_format.rs != 29 || ip->i_format.rt != 29) if (ip->i_format.rs != 29 || ip->i_format.rt != 29)
return 0; return 0;
if (ip->i_format.opcode == addiu_op || ip->i_format.opcode == daddiu_op) if (ip->i_format.opcode == addiu_op || ip->i_format.opcode == daddiu_op)
return 1; return 1;
#endif
return 0; return 0;
} }
static int get_frame_info(struct mips_frame_info *info) static int get_frame_info(struct mips_frame_info *info)
{ {
#ifdef CONFIG_CPU_MICROMIPS
union mips_instruction *ip = (void *) (((char *) info->func) - 1);
#else
union mips_instruction *ip = info->func; union mips_instruction *ip = info->func;
#endif
unsigned max_insns = info->func_size / sizeof(union mips_instruction); unsigned max_insns = info->func_size / sizeof(union mips_instruction);
unsigned i; unsigned i;
...@@ -290,7 +372,26 @@ static int get_frame_info(struct mips_frame_info *info) ...@@ -290,7 +372,26 @@ static int get_frame_info(struct mips_frame_info *info)
break; break;
if (!info->frame_size) { if (!info->frame_size) {
if (is_sp_move_ins(ip)) if (is_sp_move_ins(ip))
{
#ifdef CONFIG_CPU_MICROMIPS
if (mm_insn_16bit(ip->halfword[0]))
{
unsigned short tmp;
if (ip->halfword[0] & mm_addiusp_func)
{
tmp = (((ip->halfword[0] >> 1) & 0x1ff) << 2);
info->frame_size = -(signed short)(tmp | ((tmp & 0x100) ? 0xfe00 : 0));
} else {
tmp = (ip->halfword[0] >> 1);
info->frame_size = -(signed short)(tmp & 0xf);
}
ip = (void *) &ip->halfword[1];
ip--;
} else
#endif
info->frame_size = - ip->i_format.simmediate; info->frame_size = - ip->i_format.simmediate;
}
continue; continue;
} }
if (info->pc_offset == -1 && is_ra_save_ins(ip)) { if (info->pc_offset == -1 && is_ra_save_ins(ip)) {
......
...@@ -138,9 +138,18 @@ stackargs: ...@@ -138,9 +138,18 @@ stackargs:
5: jr t1 5: jr t1
sw t5, 16(sp) # argument #5 to ksp sw t5, 16(sp) # argument #5 to ksp
#ifdef CONFIG_CPU_MICROMIPS
sw t8, 28(sp) # argument #8 to ksp sw t8, 28(sp) # argument #8 to ksp
nop
sw t7, 24(sp) # argument #7 to ksp sw t7, 24(sp) # argument #7 to ksp
nop
sw t6, 20(sp) # argument #6 to ksp sw t6, 20(sp) # argument #6 to ksp
nop
#else
sw t8, 28(sp) # argument #8 to ksp
sw t7, 24(sp) # argument #7 to ksp
sw t6, 20(sp) # argument #6 to ksp
#endif
6: j stack_done # go back 6: j stack_done # go back
nop nop
.set pop .set pop
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <asm/war.h> #include <asm/war.h>
#include <asm/vdso.h> #include <asm/vdso.h>
#include <asm/dsp.h> #include <asm/dsp.h>
#include <asm/inst.h>
#include "signal-common.h" #include "signal-common.h"
...@@ -480,7 +481,15 @@ static void handle_signal(unsigned long sig, siginfo_t *info, ...@@ -480,7 +481,15 @@ static void handle_signal(unsigned long sig, siginfo_t *info,
sigset_t *oldset = sigmask_to_save(); sigset_t *oldset = sigmask_to_save();
int ret; int ret;
struct mips_abi *abi = current->thread.abi; struct mips_abi *abi = current->thread.abi;
#ifdef CONFIG_CPU_MICROMIPS
void *vdso;
unsigned int tmp = (unsigned int)current->mm->context.vdso;
set_isa16_mode(tmp);
vdso = (void *)tmp;
#else
void *vdso = current->mm->context.vdso; void *vdso = current->mm->context.vdso;
#endif
if (regs->regs[0]) { if (regs->regs[0]) {
switch(regs->regs[2]) { switch(regs->regs[2]) {
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <asm/mipsregs.h> #include <asm/mipsregs.h>
#include <asm/mipsmtregs.h> #include <asm/mipsmtregs.h>
#include <asm/mips_mt.h> #include <asm/mips_mt.h>
#include <asm/gic.h>
static void __init smvp_copy_vpe_config(void) static void __init smvp_copy_vpe_config(void)
{ {
...@@ -151,8 +152,6 @@ static void vsmp_send_ipi_mask(const struct cpumask *mask, unsigned int action) ...@@ -151,8 +152,6 @@ static void vsmp_send_ipi_mask(const struct cpumask *mask, unsigned int action)
static void __cpuinit vsmp_init_secondary(void) static void __cpuinit vsmp_init_secondary(void)
{ {
#ifdef CONFIG_IRQ_GIC #ifdef CONFIG_IRQ_GIC
extern int gic_present;
/* This is Malta specific: IPI,performance and timer interrupts */ /* This is Malta specific: IPI,performance and timer interrupts */
if (gic_present) if (gic_present)
change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 |
......
...@@ -49,6 +49,9 @@ CAN WE PROVE THAT WE WON'T DO THIS IF INTS DISABLED?? ...@@ -49,6 +49,9 @@ CAN WE PROVE THAT WE WON'T DO THIS IF INTS DISABLED??
.text .text
.align 5 .align 5
FEXPORT(__smtc_ipi_vector) FEXPORT(__smtc_ipi_vector)
#ifdef CONFIG_CPU_MICROMIPS
nop
#endif
.set noat .set noat
/* Disable thread scheduling to make Status update atomic */ /* Disable thread scheduling to make Status update atomic */
DMT 27 # dmt k1 DMT 27 # dmt k1
......
...@@ -111,7 +111,7 @@ static int vpe0limit; ...@@ -111,7 +111,7 @@ static int vpe0limit;
static int ipibuffers; static int ipibuffers;
static int nostlb; static int nostlb;
static int asidmask; static int asidmask;
unsigned long smtc_asid_mask = 0xff; unsigned int smtc_asid_mask = 0xff;
static int __init vpe0tcs(char *str) static int __init vpe0tcs(char *str)
{ {
...@@ -1395,7 +1395,7 @@ void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) ...@@ -1395,7 +1395,7 @@ void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu)
asid = asid_cache(cpu); asid = asid_cache(cpu);
do { do {
if (!((asid += ASID_INC) & ASID_MASK) ) { if (!ASID_MASK(ASID_INC(asid))) {
if (cpu_has_vtag_icache) if (cpu_has_vtag_icache)
flush_icache_all(); flush_icache_all();
/* Traverse all online CPUs (hack requires contiguous range) */ /* Traverse all online CPUs (hack requires contiguous range) */
...@@ -1414,7 +1414,7 @@ void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) ...@@ -1414,7 +1414,7 @@ void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu)
mips_ihb(); mips_ihb();
} }
tcstat = read_tc_c0_tcstatus(); tcstat = read_tc_c0_tcstatus();
smtc_live_asid[tlb][(tcstat & ASID_MASK)] |= (asiduse)(0x1 << i); smtc_live_asid[tlb][ASID_MASK(tcstat)] |= (asiduse)(0x1 << i);
if (!prevhalt) if (!prevhalt)
write_tc_c0_tchalt(0); write_tc_c0_tchalt(0);
} }
...@@ -1423,7 +1423,7 @@ void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) ...@@ -1423,7 +1423,7 @@ void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu)
asid = ASID_FIRST_VERSION; asid = ASID_FIRST_VERSION;
local_flush_tlb_all(); /* start new asid cycle */ local_flush_tlb_all(); /* start new asid cycle */
} }
} while (smtc_live_asid[tlb][(asid & ASID_MASK)]); } while (smtc_live_asid[tlb][ASID_MASK(asid)]);
/* /*
* SMTC shares the TLB within VPEs and possibly across all VPEs. * SMTC shares the TLB within VPEs and possibly across all VPEs.
...@@ -1461,7 +1461,7 @@ void smtc_flush_tlb_asid(unsigned long asid) ...@@ -1461,7 +1461,7 @@ void smtc_flush_tlb_asid(unsigned long asid)
tlb_read(); tlb_read();
ehb(); ehb();
ehi = read_c0_entryhi(); ehi = read_c0_entryhi();
if ((ehi & ASID_MASK) == asid) { if (ASID_MASK(ehi) == asid) {
/* /*
* Invalidate only entries with specified ASID, * Invalidate only entries with specified ASID,
* makiing sure all entries differ. * makiing sure all entries differ.
......
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
* Copyright (C) 1998 Ulf Carlsson * Copyright (C) 1998 Ulf Carlsson
* Copyright (C) 1999 Silicon Graphics, Inc. * Copyright (C) 1999 Silicon Graphics, Inc.
* Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2000, 01 MIPS Technologies, Inc.
* Copyright (C) 2002, 2003, 2004, 2005, 2007 Maciej W. Rozycki * Copyright (C) 2002, 2003, 2004, 2005, 2007 Maciej W. Rozycki
* Copyright (C) 2000, 2001, 2012 MIPS Technologies, Inc. All rights reserved.
*/ */
#include <linux/bug.h> #include <linux/bug.h>
#include <linux/compiler.h> #include <linux/compiler.h>
...@@ -83,10 +83,6 @@ extern asmlinkage void handle_dsp(void); ...@@ -83,10 +83,6 @@ extern asmlinkage void handle_dsp(void);
extern asmlinkage void handle_mcheck(void); extern asmlinkage void handle_mcheck(void);
extern asmlinkage void handle_reserved(void); extern asmlinkage void handle_reserved(void);
extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
struct mips_fpu_struct *ctx, int has_fpu,
void *__user *fault_addr);
void (*board_be_init)(void); void (*board_be_init)(void);
int (*board_be_handler)(struct pt_regs *regs, int is_fixup); int (*board_be_handler)(struct pt_regs *regs, int is_fixup);
void (*board_nmi_handler_setup)(void); void (*board_nmi_handler_setup)(void);
...@@ -495,6 +491,12 @@ asmlinkage void do_be(struct pt_regs *regs) ...@@ -495,6 +491,12 @@ asmlinkage void do_be(struct pt_regs *regs)
#define SYNC 0x0000000f #define SYNC 0x0000000f
#define RDHWR 0x0000003b #define RDHWR 0x0000003b
/* microMIPS definitions */
#define MM_POOL32A_FUNC 0xfc00ffff
#define MM_RDHWR 0x00006b3c
#define MM_RS 0x001f0000
#define MM_RT 0x03e00000
/* /*
* The ll_bit is cleared by r*_switch.S * The ll_bit is cleared by r*_switch.S
*/ */
...@@ -609,42 +611,62 @@ static int simulate_llsc(struct pt_regs *regs, unsigned int opcode) ...@@ -609,42 +611,62 @@ static int simulate_llsc(struct pt_regs *regs, unsigned int opcode)
* Simulate trapping 'rdhwr' instructions to provide user accessible * Simulate trapping 'rdhwr' instructions to provide user accessible
* registers not implemented in hardware. * registers not implemented in hardware.
*/ */
static int simulate_rdhwr(struct pt_regs *regs, unsigned int opcode) static int simulate_rdhwr(struct pt_regs *regs, int rd, int rt)
{ {
struct thread_info *ti = task_thread_info(current); struct thread_info *ti = task_thread_info(current);
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS,
1, regs, 0);
switch (rd) {
case 0: /* CPU number */
regs->regs[rt] = smp_processor_id();
return 0;
case 1: /* SYNCI length */
regs->regs[rt] = min(current_cpu_data.dcache.linesz,
current_cpu_data.icache.linesz);
return 0;
case 2: /* Read count register */
regs->regs[rt] = read_c0_count();
return 0;
case 3: /* Count register resolution */
switch (current_cpu_data.cputype) {
case CPU_20KC:
case CPU_25KF:
regs->regs[rt] = 1;
break;
default:
regs->regs[rt] = 2;
}
return 0;
case 29:
regs->regs[rt] = ti->tp_value;
return 0;
default:
return -1;
}
}
static int simulate_rdhwr_normal(struct pt_regs *regs, unsigned int opcode)
{
if ((opcode & OPCODE) == SPEC3 && (opcode & FUNC) == RDHWR) { if ((opcode & OPCODE) == SPEC3 && (opcode & FUNC) == RDHWR) {
int rd = (opcode & RD) >> 11; int rd = (opcode & RD) >> 11;
int rt = (opcode & RT) >> 16; int rt = (opcode & RT) >> 16;
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS,
1, regs, 0); simulate_rdhwr(regs, rd, rt);
switch (rd) { return 0;
case 0: /* CPU number */ }
regs->regs[rt] = smp_processor_id();
return 0; /* Not ours. */
case 1: /* SYNCI length */ return -1;
regs->regs[rt] = min(current_cpu_data.dcache.linesz, }
current_cpu_data.icache.linesz);
return 0; static int simulate_rdhwr_mm(struct pt_regs *regs, unsigned short opcode)
case 2: /* Read count register */ {
regs->regs[rt] = read_c0_count(); if ((opcode & MM_POOL32A_FUNC) == MM_RDHWR) {
return 0; int rd = (opcode & MM_RS) >> 16;
case 3: /* Count register resolution */ int rt = (opcode & MM_RT) >> 21;
switch (current_cpu_data.cputype) { simulate_rdhwr(regs, rd, rt);
case CPU_20KC: return 0;
case CPU_25KF:
regs->regs[rt] = 1;
break;
default:
regs->regs[rt] = 2;
}
return 0;
case 29:
regs->regs[rt] = ti->tp_value;
return 0;
default:
return -1;
}
} }
/* Not ours. */ /* Not ours. */
...@@ -675,7 +697,7 @@ asmlinkage void do_ov(struct pt_regs *regs) ...@@ -675,7 +697,7 @@ asmlinkage void do_ov(struct pt_regs *regs)
force_sig_info(SIGFPE, &info, current); force_sig_info(SIGFPE, &info, current);
} }
static int process_fpemu_return(int sig, void __user *fault_addr) int process_fpemu_return(int sig, void __user *fault_addr)
{ {
if (sig == SIGSEGV || sig == SIGBUS) { if (sig == SIGSEGV || sig == SIGBUS) {
struct siginfo si = {0}; struct siginfo si = {0};
...@@ -826,9 +848,29 @@ static void do_trap_or_bp(struct pt_regs *regs, unsigned int code, ...@@ -826,9 +848,29 @@ static void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
asmlinkage void do_bp(struct pt_regs *regs) asmlinkage void do_bp(struct pt_regs *regs)
{ {
unsigned int opcode, bcode; unsigned int opcode, bcode;
unsigned long epc;
if (__get_user(opcode, (unsigned int __user *) exception_epc(regs))) u16 instr[2];
goto out_sigsegv;
if (get_isa16_mode(regs->cp0_epc)) {
/* Calculate EPC. */
epc = exception_epc(regs);
if (cpu_has_mmips) {
if ((__get_user(instr[0], (u16 __user *)msk_isa16_mode(epc)) ||
(__get_user(instr[1], (u16 __user *)msk_isa16_mode(epc + 2)))))
goto out_sigsegv;
opcode = (instr[0] << 16) | instr[1];
} else {
/* MIPS16e mode */
if (__get_user(instr[0], (u16 __user *)msk_isa16_mode(epc)))
goto out_sigsegv;
bcode = (instr[0] >> 6) & 0x3f;
do_trap_or_bp(regs, bcode, "Break");
return;
}
} else {
if (__get_user(opcode, (unsigned int __user *) exception_epc(regs)))
goto out_sigsegv;
}
/* /*
* There is the ancient bug in the MIPS assemblers that the break * There is the ancient bug in the MIPS assemblers that the break
...@@ -869,13 +911,22 @@ asmlinkage void do_bp(struct pt_regs *regs) ...@@ -869,13 +911,22 @@ asmlinkage void do_bp(struct pt_regs *regs)
asmlinkage void do_tr(struct pt_regs *regs) asmlinkage void do_tr(struct pt_regs *regs)
{ {
unsigned int opcode, tcode = 0; unsigned int opcode, tcode = 0;
u16 instr[2];
unsigned long epc = exception_epc(regs);
if (__get_user(opcode, (unsigned int __user *) exception_epc(regs))) if ((__get_user(instr[0], (u16 __user *)msk_isa16_mode(epc))) ||
goto out_sigsegv; (__get_user(instr[1], (u16 __user *)msk_isa16_mode(epc + 2))))
goto out_sigsegv;
opcode = (instr[0] << 16) | instr[1];
/* Immediate versions don't provide a code. */ /* Immediate versions don't provide a code. */
if (!(opcode & OPCODE)) if (!(opcode & OPCODE)) {
tcode = ((opcode >> 6) & ((1 << 10) - 1)); if (get_isa16_mode(regs->cp0_epc))
/* microMIPS */
tcode = (opcode >> 12) & 0x1f;
else
tcode = ((opcode >> 6) & ((1 << 10) - 1));
}
do_trap_or_bp(regs, tcode, "Trap"); do_trap_or_bp(regs, tcode, "Trap");
return; return;
...@@ -888,6 +939,7 @@ asmlinkage void do_ri(struct pt_regs *regs) ...@@ -888,6 +939,7 @@ asmlinkage void do_ri(struct pt_regs *regs)
{ {
unsigned int __user *epc = (unsigned int __user *)exception_epc(regs); unsigned int __user *epc = (unsigned int __user *)exception_epc(regs);
unsigned long old_epc = regs->cp0_epc; unsigned long old_epc = regs->cp0_epc;
unsigned long old31 = regs->regs[31];
unsigned int opcode = 0; unsigned int opcode = 0;
int status = -1; int status = -1;
...@@ -900,23 +952,37 @@ asmlinkage void do_ri(struct pt_regs *regs) ...@@ -900,23 +952,37 @@ asmlinkage void do_ri(struct pt_regs *regs)
if (unlikely(compute_return_epc(regs) < 0)) if (unlikely(compute_return_epc(regs) < 0))
return; return;
if (unlikely(get_user(opcode, epc) < 0)) if (get_isa16_mode(regs->cp0_epc)) {
status = SIGSEGV; unsigned short mmop[2] = { 0 };
if (!cpu_has_llsc && status < 0) if (unlikely(get_user(mmop[0], epc) < 0))
status = simulate_llsc(regs, opcode); status = SIGSEGV;
if (unlikely(get_user(mmop[1], epc) < 0))
status = SIGSEGV;
opcode = (mmop[0] << 16) | mmop[1];
if (status < 0) if (status < 0)
status = simulate_rdhwr(regs, opcode); status = simulate_rdhwr_mm(regs, opcode);
} else {
if (unlikely(get_user(opcode, epc) < 0))
status = SIGSEGV;
if (status < 0) if (!cpu_has_llsc && status < 0)
status = simulate_sync(regs, opcode); status = simulate_llsc(regs, opcode);
if (status < 0)
status = simulate_rdhwr_normal(regs, opcode);
if (status < 0)
status = simulate_sync(regs, opcode);
}
if (status < 0) if (status < 0)
status = SIGILL; status = SIGILL;
if (unlikely(status > 0)) { if (unlikely(status > 0)) {
regs->cp0_epc = old_epc; /* Undo skip-over. */ regs->cp0_epc = old_epc; /* Undo skip-over. */
regs->regs[31] = old31;
force_sig(status, current); force_sig(status, current);
} }
} }
...@@ -986,7 +1052,7 @@ static int default_cu2_call(struct notifier_block *nfb, unsigned long action, ...@@ -986,7 +1052,7 @@ static int default_cu2_call(struct notifier_block *nfb, unsigned long action,
asmlinkage void do_cpu(struct pt_regs *regs) asmlinkage void do_cpu(struct pt_regs *regs)
{ {
unsigned int __user *epc; unsigned int __user *epc;
unsigned long old_epc; unsigned long old_epc, old31;
unsigned int opcode; unsigned int opcode;
unsigned int cpid; unsigned int cpid;
int status; int status;
...@@ -1000,26 +1066,41 @@ asmlinkage void do_cpu(struct pt_regs *regs) ...@@ -1000,26 +1066,41 @@ asmlinkage void do_cpu(struct pt_regs *regs)
case 0: case 0:
epc = (unsigned int __user *)exception_epc(regs); epc = (unsigned int __user *)exception_epc(regs);
old_epc = regs->cp0_epc; old_epc = regs->cp0_epc;
old31 = regs->regs[31];
opcode = 0; opcode = 0;
status = -1; status = -1;
if (unlikely(compute_return_epc(regs) < 0)) if (unlikely(compute_return_epc(regs) < 0))
return; return;
if (unlikely(get_user(opcode, epc) < 0)) if (get_isa16_mode(regs->cp0_epc)) {
status = SIGSEGV; unsigned short mmop[2] = { 0 };
if (!cpu_has_llsc && status < 0) if (unlikely(get_user(mmop[0], epc) < 0))
status = simulate_llsc(regs, opcode); status = SIGSEGV;
if (unlikely(get_user(mmop[1], epc) < 0))
status = SIGSEGV;
opcode = (mmop[0] << 16) | mmop[1];
if (status < 0) if (status < 0)
status = simulate_rdhwr(regs, opcode); status = simulate_rdhwr_mm(regs, opcode);
} else {
if (unlikely(get_user(opcode, epc) < 0))
status = SIGSEGV;
if (!cpu_has_llsc && status < 0)
status = simulate_llsc(regs, opcode);
if (status < 0)
status = simulate_rdhwr_normal(regs, opcode);
}
if (status < 0) if (status < 0)
status = SIGILL; status = SIGILL;
if (unlikely(status > 0)) { if (unlikely(status > 0)) {
regs->cp0_epc = old_epc; /* Undo skip-over. */ regs->cp0_epc = old_epc; /* Undo skip-over. */
regs->regs[31] = old31;
force_sig(status, current); force_sig(status, current);
} }
...@@ -1333,7 +1414,7 @@ asmlinkage void cache_parity_error(void) ...@@ -1333,7 +1414,7 @@ asmlinkage void cache_parity_error(void)
void ejtag_exception_handler(struct pt_regs *regs) void ejtag_exception_handler(struct pt_regs *regs)
{ {
const int field = 2 * sizeof(unsigned long); const int field = 2 * sizeof(unsigned long);
unsigned long depc, old_epc; unsigned long depc, old_epc, old_ra;
unsigned int debug; unsigned int debug;
printk(KERN_DEBUG "SDBBP EJTAG debug exception - not handled yet, just ignored!\n"); printk(KERN_DEBUG "SDBBP EJTAG debug exception - not handled yet, just ignored!\n");
...@@ -1348,10 +1429,12 @@ void ejtag_exception_handler(struct pt_regs *regs) ...@@ -1348,10 +1429,12 @@ void ejtag_exception_handler(struct pt_regs *regs)
* calculation. * calculation.
*/ */
old_epc = regs->cp0_epc; old_epc = regs->cp0_epc;
old_ra = regs->regs[31];
regs->cp0_epc = depc; regs->cp0_epc = depc;
__compute_return_epc(regs); compute_return_epc(regs);
depc = regs->cp0_epc; depc = regs->cp0_epc;
regs->cp0_epc = old_epc; regs->cp0_epc = old_epc;
regs->regs[31] = old_ra;
} else } else
depc += 4; depc += 4;
write_c0_depc(depc); write_c0_depc(depc);
...@@ -1390,10 +1473,27 @@ unsigned long vi_handlers[64]; ...@@ -1390,10 +1473,27 @@ unsigned long vi_handlers[64];
void __init *set_except_vector(int n, void *addr) void __init *set_except_vector(int n, void *addr)
{ {
unsigned long handler = (unsigned long) addr; unsigned long handler = (unsigned long) addr;
unsigned long old_handler = xchg(&exception_handlers[n], handler); unsigned long old_handler;
#ifdef CONFIG_CPU_MICROMIPS
/*
* Only the TLB handlers are cache aligned with an even
* address. All other handlers are on an odd address and
* require no modification. Otherwise, MIPS32 mode will
* be entered when handling any TLB exceptions. That
* would be bad...since we must stay in microMIPS mode.
*/
if (!(handler & 0x1))
handler |= 1;
#endif
old_handler = xchg(&exception_handlers[n], handler);
if (n == 0 && cpu_has_divec) { if (n == 0 && cpu_has_divec) {
#ifdef CONFIG_CPU_MICROMIPS
unsigned long jump_mask = ~((1 << 27) - 1);
#else
unsigned long jump_mask = ~((1 << 28) - 1); unsigned long jump_mask = ~((1 << 28) - 1);
#endif
u32 *buf = (u32 *)(ebase + 0x200); u32 *buf = (u32 *)(ebase + 0x200);
unsigned int k0 = 26; unsigned int k0 = 26;
if ((handler & jump_mask) == ((ebase + 0x200) & jump_mask)) { if ((handler & jump_mask) == ((ebase + 0x200) & jump_mask)) {
...@@ -1420,17 +1520,18 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) ...@@ -1420,17 +1520,18 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs)
unsigned long handler; unsigned long handler;
unsigned long old_handler = vi_handlers[n]; unsigned long old_handler = vi_handlers[n];
int srssets = current_cpu_data.srsets; int srssets = current_cpu_data.srsets;
u32 *w; u16 *h;
unsigned char *b; unsigned char *b;
BUG_ON(!cpu_has_veic && !cpu_has_vint); BUG_ON(!cpu_has_veic && !cpu_has_vint);
BUG_ON((n < 0) && (n > 9));
if (addr == NULL) { if (addr == NULL) {
handler = (unsigned long) do_default_vi; handler = (unsigned long) do_default_vi;
srs = 0; srs = 0;
} else } else
handler = (unsigned long) addr; handler = (unsigned long) addr;
vi_handlers[n] = (unsigned long) addr; vi_handlers[n] = handler;
b = (unsigned char *)(ebase + 0x200 + n*VECTORSPACING); b = (unsigned char *)(ebase + 0x200 + n*VECTORSPACING);
...@@ -1449,9 +1550,8 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) ...@@ -1449,9 +1550,8 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs)
if (srs == 0) { if (srs == 0) {
/* /*
* If no shadow set is selected then use the default handler * If no shadow set is selected then use the default handler
* that does normal register saving and a standard interrupt exit * that does normal register saving and standard interrupt exit
*/ */
extern char except_vec_vi, except_vec_vi_lui; extern char except_vec_vi, except_vec_vi_lui;
extern char except_vec_vi_ori, except_vec_vi_end; extern char except_vec_vi_ori, except_vec_vi_end;
extern char rollback_except_vec_vi; extern char rollback_except_vec_vi;
...@@ -1464,11 +1564,20 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) ...@@ -1464,11 +1564,20 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs)
* Status.IM bit to be masked before going there. * Status.IM bit to be masked before going there.
*/ */
extern char except_vec_vi_mori; extern char except_vec_vi_mori;
#if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_BIG_ENDIAN)
const int mori_offset = &except_vec_vi_mori - vec_start + 2;
#else
const int mori_offset = &except_vec_vi_mori - vec_start; const int mori_offset = &except_vec_vi_mori - vec_start;
#endif
#endif /* CONFIG_MIPS_MT_SMTC */ #endif /* CONFIG_MIPS_MT_SMTC */
const int handler_len = &except_vec_vi_end - vec_start; #if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_BIG_ENDIAN)
const int lui_offset = &except_vec_vi_lui - vec_start + 2;
const int ori_offset = &except_vec_vi_ori - vec_start + 2;
#else
const int lui_offset = &except_vec_vi_lui - vec_start; const int lui_offset = &except_vec_vi_lui - vec_start;
const int ori_offset = &except_vec_vi_ori - vec_start; const int ori_offset = &except_vec_vi_ori - vec_start;
#endif
const int handler_len = &except_vec_vi_end - vec_start;
if (handler_len > VECTORSPACING) { if (handler_len > VECTORSPACING) {
/* /*
...@@ -1478,30 +1587,44 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) ...@@ -1478,30 +1587,44 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs)
panic("VECTORSPACING too small"); panic("VECTORSPACING too small");
} }
memcpy(b, vec_start, handler_len); set_handler(((unsigned long)b - ebase), vec_start,
#ifdef CONFIG_CPU_MICROMIPS
(handler_len - 1));
#else
handler_len);
#endif
#ifdef CONFIG_MIPS_MT_SMTC #ifdef CONFIG_MIPS_MT_SMTC
BUG_ON(n > 7); /* Vector index %d exceeds SMTC maximum. */ BUG_ON(n > 7); /* Vector index %d exceeds SMTC maximum. */
w = (u32 *)(b + mori_offset); h = (u16 *)(b + mori_offset);
*w = (*w & 0xffff0000) | (0x100 << n); *h = (0x100 << n);
#endif /* CONFIG_MIPS_MT_SMTC */ #endif /* CONFIG_MIPS_MT_SMTC */
w = (u32 *)(b + lui_offset); h = (u16 *)(b + lui_offset);
*w = (*w & 0xffff0000) | (((u32)handler >> 16) & 0xffff); *h = (handler >> 16) & 0xffff;
w = (u32 *)(b + ori_offset); h = (u16 *)(b + ori_offset);
*w = (*w & 0xffff0000) | ((u32)handler & 0xffff); *h = (handler & 0xffff);
local_flush_icache_range((unsigned long)b, local_flush_icache_range((unsigned long)b,
(unsigned long)(b+handler_len)); (unsigned long)(b+handler_len));
} }
else { else {
/* /*
* In other cases jump directly to the interrupt handler * In other cases jump directly to the interrupt handler. It
* * is the handler's responsibility to save registers if required
* It is the handlers responsibility to save registers if required * (eg hi/lo) and return from the exception using "eret".
* (eg hi/lo) and return from the exception using "eret"
*/ */
w = (u32 *)b; u32 insn;
*w++ = 0x08000000 | (((u32)handler >> 2) & 0x03fffff); /* j handler */
*w = 0; h = (u16 *)b;
/* j handler */
#ifdef CONFIG_CPU_MICROMIPS
insn = 0xd4000000 | (((u32)handler & 0x07ffffff) >> 1);
#else
insn = 0x08000000 | (((u32)handler & 0x0fffffff) >> 2);
#endif
h[0] = (insn >> 16) & 0xffff;
h[1] = insn & 0xffff;
h[2] = 0;
h[3] = 0;
local_flush_icache_range((unsigned long)b, local_flush_icache_range((unsigned long)b,
(unsigned long)(b+8)); (unsigned long)(b+8));
} }
...@@ -1546,6 +1669,7 @@ void __cpuinit per_cpu_trap_init(bool is_boot_cpu) ...@@ -1546,6 +1669,7 @@ void __cpuinit per_cpu_trap_init(bool is_boot_cpu)
unsigned int cpu = smp_processor_id(); unsigned int cpu = smp_processor_id();
unsigned int status_set = ST0_CU0; unsigned int status_set = ST0_CU0;
unsigned int hwrena = cpu_hwrena_impl_bits; unsigned int hwrena = cpu_hwrena_impl_bits;
unsigned long asid = 0;
#ifdef CONFIG_MIPS_MT_SMTC #ifdef CONFIG_MIPS_MT_SMTC
int secondaryTC = 0; int secondaryTC = 0;
int bootTC = (cpu == 0); int bootTC = (cpu == 0);
...@@ -1629,8 +1753,9 @@ void __cpuinit per_cpu_trap_init(bool is_boot_cpu) ...@@ -1629,8 +1753,9 @@ void __cpuinit per_cpu_trap_init(bool is_boot_cpu)
} }
#endif /* CONFIG_MIPS_MT_SMTC */ #endif /* CONFIG_MIPS_MT_SMTC */
if (!cpu_data[cpu].asid_cache) asid = ASID_FIRST_VERSION;
cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; cpu_data[cpu].asid_cache = asid;
TLBMISS_HANDLER_SETUP();
atomic_inc(&init_mm.mm_count); atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm; current->active_mm = &init_mm;
...@@ -1660,7 +1785,11 @@ void __cpuinit per_cpu_trap_init(bool is_boot_cpu) ...@@ -1660,7 +1785,11 @@ void __cpuinit per_cpu_trap_init(bool is_boot_cpu)
/* Install CPU exception handler */ /* Install CPU exception handler */
void __cpuinit set_handler(unsigned long offset, void *addr, unsigned long size) void __cpuinit set_handler(unsigned long offset, void *addr, unsigned long size)
{ {
#ifdef CONFIG_CPU_MICROMIPS
memcpy((void *)(ebase + offset), ((unsigned char *)addr - 1), size);
#else
memcpy((void *)(ebase + offset), addr, size); memcpy((void *)(ebase + offset), addr, size);
#endif
local_flush_icache_range(ebase + offset, ebase + offset + size); local_flush_icache_range(ebase + offset, ebase + offset + size);
} }
...@@ -1694,8 +1823,9 @@ __setup("rdhwr_noopt", set_rdhwr_noopt); ...@@ -1694,8 +1823,9 @@ __setup("rdhwr_noopt", set_rdhwr_noopt);
void __init trap_init(void) void __init trap_init(void)
{ {
extern char except_vec3_generic, except_vec3_r4000; extern char except_vec3_generic;
extern char except_vec4; extern char except_vec4;
extern char except_vec3_r4000;
unsigned long i; unsigned long i;
int rollback; int rollback;
...@@ -1833,11 +1963,11 @@ void __init trap_init(void) ...@@ -1833,11 +1963,11 @@ void __init trap_init(void)
if (cpu_has_vce) if (cpu_has_vce)
/* Special exception: R4[04]00 uses also the divec space. */ /* Special exception: R4[04]00 uses also the divec space. */
memcpy((void *)(ebase + 0x180), &except_vec3_r4000, 0x100); set_handler(0x180, &except_vec3_r4000, 0x100);
else if (cpu_has_4kex) else if (cpu_has_4kex)
memcpy((void *)(ebase + 0x180), &except_vec3_generic, 0x80); set_handler(0x180, &except_vec3_generic, 0x80);
else else
memcpy((void *)(ebase + 0x080), &except_vec3_generic, 0x80); set_handler(0x080, &except_vec3_generic, 0x80);
local_flush_icache_range(ebase, ebase + 0x400); local_flush_icache_range(ebase, ebase + 0x400);
flush_tlb_handlers(); flush_tlb_handlers();
......
...@@ -83,8 +83,12 @@ ...@@ -83,8 +83,12 @@
#include <asm/branch.h> #include <asm/branch.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/cop2.h> #include <asm/cop2.h>
#include <asm/fpu.h>
#include <asm/fpu_emulator.h>
#include <asm/inst.h> #include <asm/inst.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/fpu.h>
#include <asm/fpu_emulator.h>
#define STR(x) __STR(x) #define STR(x) __STR(x)
#define __STR(x) #x #define __STR(x) #x
...@@ -102,12 +106,332 @@ static u32 unaligned_action; ...@@ -102,12 +106,332 @@ static u32 unaligned_action;
#endif #endif
extern void show_registers(struct pt_regs *regs); extern void show_registers(struct pt_regs *regs);
#ifdef __BIG_ENDIAN
#define LoadHW(addr, value, res) \
__asm__ __volatile__ (".set\tnoat\n" \
"1:\tlb\t%0, 0(%2)\n" \
"2:\tlbu\t$1, 1(%2)\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
"3:\t.set\tat\n\t" \
".insn\n\t" \
".section\t.fixup,\"ax\"\n\t" \
"4:\tli\t%1, %3\n\t" \
"j\t3b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 4b\n\t" \
STR(PTR)"\t2b, 4b\n\t" \
".previous" \
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#define LoadW(addr, value, res) \
__asm__ __volatile__ ( \
"1:\tlwl\t%0, (%2)\n" \
"2:\tlwr\t%0, 3(%2)\n\t" \
"li\t%1, 0\n" \
"3:\n\t" \
".insn\n\t" \
".section\t.fixup,\"ax\"\n\t" \
"4:\tli\t%1, %3\n\t" \
"j\t3b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 4b\n\t" \
STR(PTR)"\t2b, 4b\n\t" \
".previous" \
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#define LoadHWU(addr, value, res) \
__asm__ __volatile__ ( \
".set\tnoat\n" \
"1:\tlbu\t%0, 0(%2)\n" \
"2:\tlbu\t$1, 1(%2)\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
"3:\n\t" \
".insn\n\t" \
".set\tat\n\t" \
".section\t.fixup,\"ax\"\n\t" \
"4:\tli\t%1, %3\n\t" \
"j\t3b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 4b\n\t" \
STR(PTR)"\t2b, 4b\n\t" \
".previous" \
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#define LoadWU(addr, value, res) \
__asm__ __volatile__ ( \
"1:\tlwl\t%0, (%2)\n" \
"2:\tlwr\t%0, 3(%2)\n\t" \
"dsll\t%0, %0, 32\n\t" \
"dsrl\t%0, %0, 32\n\t" \
"li\t%1, 0\n" \
"3:\n\t" \
".insn\n\t" \
"\t.section\t.fixup,\"ax\"\n\t" \
"4:\tli\t%1, %3\n\t" \
"j\t3b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 4b\n\t" \
STR(PTR)"\t2b, 4b\n\t" \
".previous" \
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#define LoadDW(addr, value, res) \
__asm__ __volatile__ ( \
"1:\tldl\t%0, (%2)\n" \
"2:\tldr\t%0, 7(%2)\n\t" \
"li\t%1, 0\n" \
"3:\n\t" \
".insn\n\t" \
"\t.section\t.fixup,\"ax\"\n\t" \
"4:\tli\t%1, %3\n\t" \
"j\t3b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 4b\n\t" \
STR(PTR)"\t2b, 4b\n\t" \
".previous" \
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#define StoreHW(addr, value, res) \
__asm__ __volatile__ ( \
".set\tnoat\n" \
"1:\tsb\t%1, 1(%2)\n\t" \
"srl\t$1, %1, 0x8\n" \
"2:\tsb\t$1, 0(%2)\n\t" \
".set\tat\n\t" \
"li\t%0, 0\n" \
"3:\n\t" \
".insn\n\t" \
".section\t.fixup,\"ax\"\n\t" \
"4:\tli\t%0, %3\n\t" \
"j\t3b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 4b\n\t" \
STR(PTR)"\t2b, 4b\n\t" \
".previous" \
: "=r" (res) \
: "r" (value), "r" (addr), "i" (-EFAULT));
#define StoreW(addr, value, res) \
__asm__ __volatile__ ( \
"1:\tswl\t%1,(%2)\n" \
"2:\tswr\t%1, 3(%2)\n\t" \
"li\t%0, 0\n" \
"3:\n\t" \
".insn\n\t" \
".section\t.fixup,\"ax\"\n\t" \
"4:\tli\t%0, %3\n\t" \
"j\t3b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 4b\n\t" \
STR(PTR)"\t2b, 4b\n\t" \
".previous" \
: "=r" (res) \
: "r" (value), "r" (addr), "i" (-EFAULT));
#define StoreDW(addr, value, res) \
__asm__ __volatile__ ( \
"1:\tsdl\t%1,(%2)\n" \
"2:\tsdr\t%1, 7(%2)\n\t" \
"li\t%0, 0\n" \
"3:\n\t" \
".insn\n\t" \
".section\t.fixup,\"ax\"\n\t" \
"4:\tli\t%0, %3\n\t" \
"j\t3b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 4b\n\t" \
STR(PTR)"\t2b, 4b\n\t" \
".previous" \
: "=r" (res) \
: "r" (value), "r" (addr), "i" (-EFAULT));
#endif
#ifdef __LITTLE_ENDIAN
#define LoadHW(addr, value, res) \
__asm__ __volatile__ (".set\tnoat\n" \
"1:\tlb\t%0, 1(%2)\n" \
"2:\tlbu\t$1, 0(%2)\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
"3:\t.set\tat\n\t" \
".insn\n\t" \
".section\t.fixup,\"ax\"\n\t" \
"4:\tli\t%1, %3\n\t" \
"j\t3b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 4b\n\t" \
STR(PTR)"\t2b, 4b\n\t" \
".previous" \
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#define LoadW(addr, value, res) \
__asm__ __volatile__ ( \
"1:\tlwl\t%0, 3(%2)\n" \
"2:\tlwr\t%0, (%2)\n\t" \
"li\t%1, 0\n" \
"3:\n\t" \
".insn\n\t" \
".section\t.fixup,\"ax\"\n\t" \
"4:\tli\t%1, %3\n\t" \
"j\t3b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 4b\n\t" \
STR(PTR)"\t2b, 4b\n\t" \
".previous" \
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#define LoadHWU(addr, value, res) \
__asm__ __volatile__ ( \
".set\tnoat\n" \
"1:\tlbu\t%0, 1(%2)\n" \
"2:\tlbu\t$1, 0(%2)\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
"3:\n\t" \
".insn\n\t" \
".set\tat\n\t" \
".section\t.fixup,\"ax\"\n\t" \
"4:\tli\t%1, %3\n\t" \
"j\t3b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 4b\n\t" \
STR(PTR)"\t2b, 4b\n\t" \
".previous" \
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#define LoadWU(addr, value, res) \
__asm__ __volatile__ ( \
"1:\tlwl\t%0, 3(%2)\n" \
"2:\tlwr\t%0, (%2)\n\t" \
"dsll\t%0, %0, 32\n\t" \
"dsrl\t%0, %0, 32\n\t" \
"li\t%1, 0\n" \
"3:\n\t" \
".insn\n\t" \
"\t.section\t.fixup,\"ax\"\n\t" \
"4:\tli\t%1, %3\n\t" \
"j\t3b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 4b\n\t" \
STR(PTR)"\t2b, 4b\n\t" \
".previous" \
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#define LoadDW(addr, value, res) \
__asm__ __volatile__ ( \
"1:\tldl\t%0, 7(%2)\n" \
"2:\tldr\t%0, (%2)\n\t" \
"li\t%1, 0\n" \
"3:\n\t" \
".insn\n\t" \
"\t.section\t.fixup,\"ax\"\n\t" \
"4:\tli\t%1, %3\n\t" \
"j\t3b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 4b\n\t" \
STR(PTR)"\t2b, 4b\n\t" \
".previous" \
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#define StoreHW(addr, value, res) \
__asm__ __volatile__ ( \
".set\tnoat\n" \
"1:\tsb\t%1, 0(%2)\n\t" \
"srl\t$1,%1, 0x8\n" \
"2:\tsb\t$1, 1(%2)\n\t" \
".set\tat\n\t" \
"li\t%0, 0\n" \
"3:\n\t" \
".insn\n\t" \
".section\t.fixup,\"ax\"\n\t" \
"4:\tli\t%0, %3\n\t" \
"j\t3b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 4b\n\t" \
STR(PTR)"\t2b, 4b\n\t" \
".previous" \
: "=r" (res) \
: "r" (value), "r" (addr), "i" (-EFAULT));
#define StoreW(addr, value, res) \
__asm__ __volatile__ ( \
"1:\tswl\t%1, 3(%2)\n" \
"2:\tswr\t%1, (%2)\n\t" \
"li\t%0, 0\n" \
"3:\n\t" \
".insn\n\t" \
".section\t.fixup,\"ax\"\n\t" \
"4:\tli\t%0, %3\n\t" \
"j\t3b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 4b\n\t" \
STR(PTR)"\t2b, 4b\n\t" \
".previous" \
: "=r" (res) \
: "r" (value), "r" (addr), "i" (-EFAULT));
#define StoreDW(addr, value, res) \
__asm__ __volatile__ ( \
"1:\tsdl\t%1, 7(%2)\n" \
"2:\tsdr\t%1, (%2)\n\t" \
"li\t%0, 0\n" \
"3:\n\t" \
".insn\n\t" \
".section\t.fixup,\"ax\"\n\t" \
"4:\tli\t%0, %3\n\t" \
"j\t3b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 4b\n\t" \
STR(PTR)"\t2b, 4b\n\t" \
".previous" \
: "=r" (res) \
: "r" (value), "r" (addr), "i" (-EFAULT));
#endif
static void emulate_load_store_insn(struct pt_regs *regs, static void emulate_load_store_insn(struct pt_regs *regs,
void __user *addr, unsigned int __user *pc) void __user *addr, unsigned int __user *pc)
{ {
union mips_instruction insn; union mips_instruction insn;
unsigned long value; unsigned long value;
unsigned int res; unsigned int res;
unsigned long origpc;
unsigned long orig31;
void __user *fault_addr = NULL;
origpc = (unsigned long)pc;
orig31 = regs->regs[31];
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0); perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0);
...@@ -117,22 +441,22 @@ static void emulate_load_store_insn(struct pt_regs *regs, ...@@ -117,22 +441,22 @@ static void emulate_load_store_insn(struct pt_regs *regs,
__get_user(insn.word, pc); __get_user(insn.word, pc);
switch (insn.i_format.opcode) { switch (insn.i_format.opcode) {
/* /*
* These are instructions that a compiler doesn't generate. We * These are instructions that a compiler doesn't generate. We
* can assume therefore that the code is MIPS-aware and * can assume therefore that the code is MIPS-aware and
* really buggy. Emulating these instructions would break the * really buggy. Emulating these instructions would break the
* semantics anyway. * semantics anyway.
*/ */
case ll_op: case ll_op:
case lld_op: case lld_op:
case sc_op: case sc_op:
case scd_op: case scd_op:
/* /*
* For these instructions the only way to create an address * For these instructions the only way to create an address
* error is an attempted access to kernel/supervisor address * error is an attempted access to kernel/supervisor address
* space. * space.
*/ */
case ldl_op: case ldl_op:
case ldr_op: case ldr_op:
case lwl_op: case lwl_op:
...@@ -146,36 +470,15 @@ static void emulate_load_store_insn(struct pt_regs *regs, ...@@ -146,36 +470,15 @@ static void emulate_load_store_insn(struct pt_regs *regs,
case sb_op: case sb_op:
goto sigbus; goto sigbus;
/* /*
* The remaining opcodes are the ones that are really of interest. * The remaining opcodes are the ones that are really of
*/ * interest.
*/
case lh_op: case lh_op:
if (!access_ok(VERIFY_READ, addr, 2)) if (!access_ok(VERIFY_READ, addr, 2))
goto sigbus; goto sigbus;
__asm__ __volatile__ (".set\tnoat\n" LoadHW(addr, value, res);
#ifdef __BIG_ENDIAN
"1:\tlb\t%0, 0(%2)\n"
"2:\tlbu\t$1, 1(%2)\n\t"
#endif
#ifdef __LITTLE_ENDIAN
"1:\tlb\t%0, 1(%2)\n"
"2:\tlbu\t$1, 0(%2)\n\t"
#endif
"sll\t%0, 0x8\n\t"
"or\t%0, $1\n\t"
"li\t%1, 0\n"
"3:\t.set\tat\n\t"
".section\t.fixup,\"ax\"\n\t"
"4:\tli\t%1, %3\n\t"
"j\t3b\n\t"
".previous\n\t"
".section\t__ex_table,\"a\"\n\t"
STR(PTR)"\t1b, 4b\n\t"
STR(PTR)"\t2b, 4b\n\t"
".previous"
: "=&r" (value), "=r" (res)
: "r" (addr), "i" (-EFAULT));
if (res) if (res)
goto fault; goto fault;
compute_return_epc(regs); compute_return_epc(regs);
...@@ -186,26 +489,7 @@ static void emulate_load_store_insn(struct pt_regs *regs, ...@@ -186,26 +489,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
if (!access_ok(VERIFY_READ, addr, 4)) if (!access_ok(VERIFY_READ, addr, 4))
goto sigbus; goto sigbus;
__asm__ __volatile__ ( LoadW(addr, value, res);
#ifdef __BIG_ENDIAN
"1:\tlwl\t%0, (%2)\n"
"2:\tlwr\t%0, 3(%2)\n\t"
#endif
#ifdef __LITTLE_ENDIAN
"1:\tlwl\t%0, 3(%2)\n"
"2:\tlwr\t%0, (%2)\n\t"
#endif
"li\t%1, 0\n"
"3:\t.section\t.fixup,\"ax\"\n\t"
"4:\tli\t%1, %3\n\t"
"j\t3b\n\t"
".previous\n\t"
".section\t__ex_table,\"a\"\n\t"
STR(PTR)"\t1b, 4b\n\t"
STR(PTR)"\t2b, 4b\n\t"
".previous"
: "=&r" (value), "=r" (res)
: "r" (addr), "i" (-EFAULT));
if (res) if (res)
goto fault; goto fault;
compute_return_epc(regs); compute_return_epc(regs);
...@@ -216,30 +500,7 @@ static void emulate_load_store_insn(struct pt_regs *regs, ...@@ -216,30 +500,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
if (!access_ok(VERIFY_READ, addr, 2)) if (!access_ok(VERIFY_READ, addr, 2))
goto sigbus; goto sigbus;
__asm__ __volatile__ ( LoadHWU(addr, value, res);
".set\tnoat\n"
#ifdef __BIG_ENDIAN
"1:\tlbu\t%0, 0(%2)\n"
"2:\tlbu\t$1, 1(%2)\n\t"
#endif
#ifdef __LITTLE_ENDIAN
"1:\tlbu\t%0, 1(%2)\n"
"2:\tlbu\t$1, 0(%2)\n\t"
#endif
"sll\t%0, 0x8\n\t"
"or\t%0, $1\n\t"
"li\t%1, 0\n"
"3:\t.set\tat\n\t"
".section\t.fixup,\"ax\"\n\t"
"4:\tli\t%1, %3\n\t"
"j\t3b\n\t"
".previous\n\t"
".section\t__ex_table,\"a\"\n\t"
STR(PTR)"\t1b, 4b\n\t"
STR(PTR)"\t2b, 4b\n\t"
".previous"
: "=&r" (value), "=r" (res)
: "r" (addr), "i" (-EFAULT));
if (res) if (res)
goto fault; goto fault;
compute_return_epc(regs); compute_return_epc(regs);
...@@ -258,28 +519,7 @@ static void emulate_load_store_insn(struct pt_regs *regs, ...@@ -258,28 +519,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
if (!access_ok(VERIFY_READ, addr, 4)) if (!access_ok(VERIFY_READ, addr, 4))
goto sigbus; goto sigbus;
__asm__ __volatile__ ( LoadWU(addr, value, res);
#ifdef __BIG_ENDIAN
"1:\tlwl\t%0, (%2)\n"
"2:\tlwr\t%0, 3(%2)\n\t"
#endif
#ifdef __LITTLE_ENDIAN
"1:\tlwl\t%0, 3(%2)\n"
"2:\tlwr\t%0, (%2)\n\t"
#endif
"dsll\t%0, %0, 32\n\t"
"dsrl\t%0, %0, 32\n\t"
"li\t%1, 0\n"
"3:\t.section\t.fixup,\"ax\"\n\t"
"4:\tli\t%1, %3\n\t"
"j\t3b\n\t"
".previous\n\t"
".section\t__ex_table,\"a\"\n\t"
STR(PTR)"\t1b, 4b\n\t"
STR(PTR)"\t2b, 4b\n\t"
".previous"
: "=&r" (value), "=r" (res)
: "r" (addr), "i" (-EFAULT));
if (res) if (res)
goto fault; goto fault;
compute_return_epc(regs); compute_return_epc(regs);
...@@ -302,26 +542,7 @@ static void emulate_load_store_insn(struct pt_regs *regs, ...@@ -302,26 +542,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
if (!access_ok(VERIFY_READ, addr, 8)) if (!access_ok(VERIFY_READ, addr, 8))
goto sigbus; goto sigbus;
__asm__ __volatile__ ( LoadDW(addr, value, res);
#ifdef __BIG_ENDIAN
"1:\tldl\t%0, (%2)\n"
"2:\tldr\t%0, 7(%2)\n\t"
#endif
#ifdef __LITTLE_ENDIAN
"1:\tldl\t%0, 7(%2)\n"
"2:\tldr\t%0, (%2)\n\t"
#endif
"li\t%1, 0\n"
"3:\t.section\t.fixup,\"ax\"\n\t"
"4:\tli\t%1, %3\n\t"
"j\t3b\n\t"
".previous\n\t"
".section\t__ex_table,\"a\"\n\t"
STR(PTR)"\t1b, 4b\n\t"
STR(PTR)"\t2b, 4b\n\t"
".previous"
: "=&r" (value), "=r" (res)
: "r" (addr), "i" (-EFAULT));
if (res) if (res)
goto fault; goto fault;
compute_return_epc(regs); compute_return_epc(regs);
...@@ -336,68 +557,22 @@ static void emulate_load_store_insn(struct pt_regs *regs, ...@@ -336,68 +557,22 @@ static void emulate_load_store_insn(struct pt_regs *regs,
if (!access_ok(VERIFY_WRITE, addr, 2)) if (!access_ok(VERIFY_WRITE, addr, 2))
goto sigbus; goto sigbus;
compute_return_epc(regs);
value = regs->regs[insn.i_format.rt]; value = regs->regs[insn.i_format.rt];
__asm__ __volatile__ ( StoreHW(addr, value, res);
#ifdef __BIG_ENDIAN
".set\tnoat\n"
"1:\tsb\t%1, 1(%2)\n\t"
"srl\t$1, %1, 0x8\n"
"2:\tsb\t$1, 0(%2)\n\t"
".set\tat\n\t"
#endif
#ifdef __LITTLE_ENDIAN
".set\tnoat\n"
"1:\tsb\t%1, 0(%2)\n\t"
"srl\t$1,%1, 0x8\n"
"2:\tsb\t$1, 1(%2)\n\t"
".set\tat\n\t"
#endif
"li\t%0, 0\n"
"3:\n\t"
".section\t.fixup,\"ax\"\n\t"
"4:\tli\t%0, %3\n\t"
"j\t3b\n\t"
".previous\n\t"
".section\t__ex_table,\"a\"\n\t"
STR(PTR)"\t1b, 4b\n\t"
STR(PTR)"\t2b, 4b\n\t"
".previous"
: "=r" (res)
: "r" (value), "r" (addr), "i" (-EFAULT));
if (res) if (res)
goto fault; goto fault;
compute_return_epc(regs);
break; break;
case sw_op: case sw_op:
if (!access_ok(VERIFY_WRITE, addr, 4)) if (!access_ok(VERIFY_WRITE, addr, 4))
goto sigbus; goto sigbus;
compute_return_epc(regs);
value = regs->regs[insn.i_format.rt]; value = regs->regs[insn.i_format.rt];
__asm__ __volatile__ ( StoreW(addr, value, res);
#ifdef __BIG_ENDIAN
"1:\tswl\t%1,(%2)\n"
"2:\tswr\t%1, 3(%2)\n\t"
#endif
#ifdef __LITTLE_ENDIAN
"1:\tswl\t%1, 3(%2)\n"
"2:\tswr\t%1, (%2)\n\t"
#endif
"li\t%0, 0\n"
"3:\n\t"
".section\t.fixup,\"ax\"\n\t"
"4:\tli\t%0, %3\n\t"
"j\t3b\n\t"
".previous\n\t"
".section\t__ex_table,\"a\"\n\t"
STR(PTR)"\t1b, 4b\n\t"
STR(PTR)"\t2b, 4b\n\t"
".previous"
: "=r" (res)
: "r" (value), "r" (addr), "i" (-EFAULT));
if (res) if (res)
goto fault; goto fault;
compute_return_epc(regs);
break; break;
case sd_op: case sd_op:
...@@ -412,31 +587,11 @@ static void emulate_load_store_insn(struct pt_regs *regs, ...@@ -412,31 +587,11 @@ static void emulate_load_store_insn(struct pt_regs *regs,
if (!access_ok(VERIFY_WRITE, addr, 8)) if (!access_ok(VERIFY_WRITE, addr, 8))
goto sigbus; goto sigbus;
compute_return_epc(regs);
value = regs->regs[insn.i_format.rt]; value = regs->regs[insn.i_format.rt];
__asm__ __volatile__ ( StoreDW(addr, value, res);
#ifdef __BIG_ENDIAN
"1:\tsdl\t%1,(%2)\n"
"2:\tsdr\t%1, 7(%2)\n\t"
#endif
#ifdef __LITTLE_ENDIAN
"1:\tsdl\t%1, 7(%2)\n"
"2:\tsdr\t%1, (%2)\n\t"
#endif
"li\t%0, 0\n"
"3:\n\t"
".section\t.fixup,\"ax\"\n\t"
"4:\tli\t%0, %3\n\t"
"j\t3b\n\t"
".previous\n\t"
".section\t__ex_table,\"a\"\n\t"
STR(PTR)"\t1b, 4b\n\t"
STR(PTR)"\t2b, 4b\n\t"
".previous"
: "=r" (res)
: "r" (value), "r" (addr), "i" (-EFAULT));
if (res) if (res)
goto fault; goto fault;
compute_return_epc(regs);
break; break;
#endif /* CONFIG_64BIT */ #endif /* CONFIG_64BIT */
...@@ -447,10 +602,21 @@ static void emulate_load_store_insn(struct pt_regs *regs, ...@@ -447,10 +602,21 @@ static void emulate_load_store_insn(struct pt_regs *regs,
case ldc1_op: case ldc1_op:
case swc1_op: case swc1_op:
case sdc1_op: case sdc1_op:
/* die_if_kernel("Unaligned FP access in kernel code", regs);
* I herewith declare: this does not happen. So send SIGBUS. BUG_ON(!used_math());
*/ BUG_ON(!is_fpu_owner());
goto sigbus;
lose_fpu(1); /* Save FPU state for the emulator. */
res = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
&fault_addr);
own_fpu(1); /* Restore FPU state. */
/* Signal if something went wrong. */
process_fpemu_return(res, fault_addr);
if (res == 0)
break;
return;
/* /*
* COP2 is available to implementor for application specific use. * COP2 is available to implementor for application specific use.
...@@ -488,6 +654,9 @@ static void emulate_load_store_insn(struct pt_regs *regs, ...@@ -488,6 +654,9 @@ static void emulate_load_store_insn(struct pt_regs *regs,
return; return;
fault: fault:
/* roll back jump/branch */
regs->cp0_epc = origpc;
regs->regs[31] = orig31;
/* Did we have an exception handler installed? */ /* Did we have an exception handler installed? */
if (fixup_exception(regs)) if (fixup_exception(regs))
return; return;
...@@ -504,10 +673,881 @@ static void emulate_load_store_insn(struct pt_regs *regs, ...@@ -504,10 +673,881 @@ static void emulate_load_store_insn(struct pt_regs *regs,
return; return;
sigill: sigill:
die_if_kernel("Unhandled kernel unaligned access or invalid instruction", regs); die_if_kernel
("Unhandled kernel unaligned access or invalid instruction", regs);
force_sig(SIGILL, current); force_sig(SIGILL, current);
} }
/* Recode table from 16-bit register notation to 32-bit GPR. */
const int reg16to32[] = { 16, 17, 2, 3, 4, 5, 6, 7 };
/* Recode table from 16-bit STORE register notation to 32-bit GPR. */
const int reg16to32st[] = { 0, 17, 2, 3, 4, 5, 6, 7 };
void emulate_load_store_microMIPS(struct pt_regs *regs, void __user * addr)
{
unsigned long value;
unsigned int res;
int i;
unsigned int reg = 0, rvar;
unsigned long orig31;
u16 __user *pc16;
u16 halfword;
unsigned int word;
unsigned long origpc, contpc;
union mips_instruction insn;
struct mm_decoded_insn mminsn;
void __user *fault_addr = NULL;
origpc = regs->cp0_epc;
orig31 = regs->regs[31];
mminsn.micro_mips_mode = 1;
/*
* This load never faults.
*/
pc16 = (unsigned short __user *)msk_isa16_mode(regs->cp0_epc);
__get_user(halfword, pc16);
pc16++;
contpc = regs->cp0_epc + 2;
word = ((unsigned int)halfword << 16);
mminsn.pc_inc = 2;
if (!mm_insn_16bit(halfword)) {
__get_user(halfword, pc16);
pc16++;
contpc = regs->cp0_epc + 4;
mminsn.pc_inc = 4;
word |= halfword;
}
mminsn.insn = word;
if (get_user(halfword, pc16))
goto fault;
mminsn.next_pc_inc = 2;
word = ((unsigned int)halfword << 16);
if (!mm_insn_16bit(halfword)) {
pc16++;
if (get_user(halfword, pc16))
goto fault;
mminsn.next_pc_inc = 4;
word |= halfword;
}
mminsn.next_insn = word;
insn = (union mips_instruction)(mminsn.insn);
if (mm_isBranchInstr(regs, mminsn, &contpc))
insn = (union mips_instruction)(mminsn.next_insn);
/* Parse instruction to find what to do */
switch (insn.mm_i_format.opcode) {
case mm_pool32a_op:
switch (insn.mm_x_format.func) {
case mm_lwxs_op:
reg = insn.mm_x_format.rd;
goto loadW;
}
goto sigbus;
case mm_pool32b_op:
switch (insn.mm_m_format.func) {
case mm_lwp_func:
reg = insn.mm_m_format.rd;
if (reg == 31)
goto sigbus;
if (!access_ok(VERIFY_READ, addr, 8))
goto sigbus;
LoadW(addr, value, res);
if (res)
goto fault;
regs->regs[reg] = value;
addr += 4;
LoadW(addr, value, res);
if (res)
goto fault;
regs->regs[reg + 1] = value;
goto success;
case mm_swp_func:
reg = insn.mm_m_format.rd;
if (reg == 31)
goto sigbus;
if (!access_ok(VERIFY_WRITE, addr, 8))
goto sigbus;
value = regs->regs[reg];
StoreW(addr, value, res);
if (res)
goto fault;
addr += 4;
value = regs->regs[reg + 1];
StoreW(addr, value, res);
if (res)
goto fault;
goto success;
case mm_ldp_func:
#ifdef CONFIG_64BIT
reg = insn.mm_m_format.rd;
if (reg == 31)
goto sigbus;
if (!access_ok(VERIFY_READ, addr, 16))
goto sigbus;
LoadDW(addr, value, res);
if (res)
goto fault;
regs->regs[reg] = value;
addr += 8;
LoadDW(addr, value, res);
if (res)
goto fault;
regs->regs[reg + 1] = value;
goto success;
#endif /* CONFIG_64BIT */
goto sigill;
case mm_sdp_func:
#ifdef CONFIG_64BIT
reg = insn.mm_m_format.rd;
if (reg == 31)
goto sigbus;
if (!access_ok(VERIFY_WRITE, addr, 16))
goto sigbus;
value = regs->regs[reg];
StoreDW(addr, value, res);
if (res)
goto fault;
addr += 8;
value = regs->regs[reg + 1];
StoreDW(addr, value, res);
if (res)
goto fault;
goto success;
#endif /* CONFIG_64BIT */
goto sigill;
case mm_lwm32_func:
reg = insn.mm_m_format.rd;
rvar = reg & 0xf;
if ((rvar > 9) || !reg)
goto sigill;
if (reg & 0x10) {
if (!access_ok
(VERIFY_READ, addr, 4 * (rvar + 1)))
goto sigbus;
} else {
if (!access_ok(VERIFY_READ, addr, 4 * rvar))
goto sigbus;
}
if (rvar == 9)
rvar = 8;
for (i = 16; rvar; rvar--, i++) {
LoadW(addr, value, res);
if (res)
goto fault;
addr += 4;
regs->regs[i] = value;
}
if ((reg & 0xf) == 9) {
LoadW(addr, value, res);
if (res)
goto fault;
addr += 4;
regs->regs[30] = value;
}
if (reg & 0x10) {
LoadW(addr, value, res);
if (res)
goto fault;
regs->regs[31] = value;
}
goto success;
case mm_swm32_func:
reg = insn.mm_m_format.rd;
rvar = reg & 0xf;
if ((rvar > 9) || !reg)
goto sigill;
if (reg & 0x10) {
if (!access_ok
(VERIFY_WRITE, addr, 4 * (rvar + 1)))
goto sigbus;
} else {
if (!access_ok(VERIFY_WRITE, addr, 4 * rvar))
goto sigbus;
}
if (rvar == 9)
rvar = 8;
for (i = 16; rvar; rvar--, i++) {
value = regs->regs[i];
StoreW(addr, value, res);
if (res)
goto fault;
addr += 4;
}
if ((reg & 0xf) == 9) {
value = regs->regs[30];
StoreW(addr, value, res);
if (res)
goto fault;
addr += 4;
}
if (reg & 0x10) {
value = regs->regs[31];
StoreW(addr, value, res);
if (res)
goto fault;
}
goto success;
case mm_ldm_func:
#ifdef CONFIG_64BIT
reg = insn.mm_m_format.rd;
rvar = reg & 0xf;
if ((rvar > 9) || !reg)
goto sigill;
if (reg & 0x10) {
if (!access_ok
(VERIFY_READ, addr, 8 * (rvar + 1)))
goto sigbus;
} else {
if (!access_ok(VERIFY_READ, addr, 8 * rvar))
goto sigbus;
}
if (rvar == 9)
rvar = 8;
for (i = 16; rvar; rvar--, i++) {
LoadDW(addr, value, res);
if (res)
goto fault;
addr += 4;
regs->regs[i] = value;
}
if ((reg & 0xf) == 9) {
LoadDW(addr, value, res);
if (res)
goto fault;
addr += 8;
regs->regs[30] = value;
}
if (reg & 0x10) {
LoadDW(addr, value, res);
if (res)
goto fault;
regs->regs[31] = value;
}
goto success;
#endif /* CONFIG_64BIT */
goto sigill;
case mm_sdm_func:
#ifdef CONFIG_64BIT
reg = insn.mm_m_format.rd;
rvar = reg & 0xf;
if ((rvar > 9) || !reg)
goto sigill;
if (reg & 0x10) {
if (!access_ok
(VERIFY_WRITE, addr, 8 * (rvar + 1)))
goto sigbus;
} else {
if (!access_ok(VERIFY_WRITE, addr, 8 * rvar))
goto sigbus;
}
if (rvar == 9)
rvar = 8;
for (i = 16; rvar; rvar--, i++) {
value = regs->regs[i];
StoreDW(addr, value, res);
if (res)
goto fault;
addr += 8;
}
if ((reg & 0xf) == 9) {
value = regs->regs[30];
StoreDW(addr, value, res);
if (res)
goto fault;
addr += 8;
}
if (reg & 0x10) {
value = regs->regs[31];
StoreDW(addr, value, res);
if (res)
goto fault;
}
goto success;
#endif /* CONFIG_64BIT */
goto sigill;
/* LWC2, SWC2, LDC2, SDC2 are not serviced */
}
goto sigbus;
case mm_pool32c_op:
switch (insn.mm_m_format.func) {
case mm_lwu_func:
reg = insn.mm_m_format.rd;
goto loadWU;
}
/* LL,SC,LLD,SCD are not serviced */
goto sigbus;
case mm_pool32f_op:
switch (insn.mm_x_format.func) {
case mm_lwxc1_func:
case mm_swxc1_func:
case mm_ldxc1_func:
case mm_sdxc1_func:
goto fpu_emul;
}
goto sigbus;
case mm_ldc132_op:
case mm_sdc132_op:
case mm_lwc132_op:
case mm_swc132_op:
fpu_emul:
/* roll back jump/branch */
regs->cp0_epc = origpc;
regs->regs[31] = orig31;
die_if_kernel("Unaligned FP access in kernel code", regs);
BUG_ON(!used_math());
BUG_ON(!is_fpu_owner());
lose_fpu(1); /* save the FPU state for the emulator */
res = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
&fault_addr);
own_fpu(1); /* restore FPU state */
/* If something went wrong, signal */
process_fpemu_return(res, fault_addr);
if (res == 0)
goto success;
return;
case mm_lh32_op:
reg = insn.mm_i_format.rt;
goto loadHW;
case mm_lhu32_op:
reg = insn.mm_i_format.rt;
goto loadHWU;
case mm_lw32_op:
reg = insn.mm_i_format.rt;
goto loadW;
case mm_sh32_op:
reg = insn.mm_i_format.rt;
goto storeHW;
case mm_sw32_op:
reg = insn.mm_i_format.rt;
goto storeW;
case mm_ld32_op:
reg = insn.mm_i_format.rt;
goto loadDW;
case mm_sd32_op:
reg = insn.mm_i_format.rt;
goto storeDW;
case mm_pool16c_op:
switch (insn.mm16_m_format.func) {
case mm_lwm16_op:
reg = insn.mm16_m_format.rlist;
rvar = reg + 1;
if (!access_ok(VERIFY_READ, addr, 4 * rvar))
goto sigbus;
for (i = 16; rvar; rvar--, i++) {
LoadW(addr, value, res);
if (res)
goto fault;
addr += 4;
regs->regs[i] = value;
}
LoadW(addr, value, res);
if (res)
goto fault;
regs->regs[31] = value;
goto success;
case mm_swm16_op:
reg = insn.mm16_m_format.rlist;
rvar = reg + 1;
if (!access_ok(VERIFY_WRITE, addr, 4 * rvar))
goto sigbus;
for (i = 16; rvar; rvar--, i++) {
value = regs->regs[i];
StoreW(addr, value, res);
if (res)
goto fault;
addr += 4;
}
value = regs->regs[31];
StoreW(addr, value, res);
if (res)
goto fault;
goto success;
}
goto sigbus;
case mm_lhu16_op:
reg = reg16to32[insn.mm16_rb_format.rt];
goto loadHWU;
case mm_lw16_op:
reg = reg16to32[insn.mm16_rb_format.rt];
goto loadW;
case mm_sh16_op:
reg = reg16to32st[insn.mm16_rb_format.rt];
goto storeHW;
case mm_sw16_op:
reg = reg16to32st[insn.mm16_rb_format.rt];
goto storeW;
case mm_lwsp16_op:
reg = insn.mm16_r5_format.rt;
goto loadW;
case mm_swsp16_op:
reg = insn.mm16_r5_format.rt;
goto storeW;
case mm_lwgp16_op:
reg = reg16to32[insn.mm16_r3_format.rt];
goto loadW;
default:
goto sigill;
}
loadHW:
if (!access_ok(VERIFY_READ, addr, 2))
goto sigbus;
LoadHW(addr, value, res);
if (res)
goto fault;
regs->regs[reg] = value;
goto success;
loadHWU:
if (!access_ok(VERIFY_READ, addr, 2))
goto sigbus;
LoadHWU(addr, value, res);
if (res)
goto fault;
regs->regs[reg] = value;
goto success;
loadW:
if (!access_ok(VERIFY_READ, addr, 4))
goto sigbus;
LoadW(addr, value, res);
if (res)
goto fault;
regs->regs[reg] = value;
goto success;
loadWU:
#ifdef CONFIG_64BIT
/*
* A 32-bit kernel might be running on a 64-bit processor. But
* if we're on a 32-bit processor and an i-cache incoherency
* or race makes us see a 64-bit instruction here the sdl/sdr
* would blow up, so for now we don't handle unaligned 64-bit
* instructions on 32-bit kernels.
*/
if (!access_ok(VERIFY_READ, addr, 4))
goto sigbus;
LoadWU(addr, value, res);
if (res)
goto fault;
regs->regs[reg] = value;
goto success;
#endif /* CONFIG_64BIT */
/* Cannot handle 64-bit instructions in 32-bit kernel */
goto sigill;
loadDW:
#ifdef CONFIG_64BIT
/*
* A 32-bit kernel might be running on a 64-bit processor. But
* if we're on a 32-bit processor and an i-cache incoherency
* or race makes us see a 64-bit instruction here the sdl/sdr
* would blow up, so for now we don't handle unaligned 64-bit
* instructions on 32-bit kernels.
*/
if (!access_ok(VERIFY_READ, addr, 8))
goto sigbus;
LoadDW(addr, value, res);
if (res)
goto fault;
regs->regs[reg] = value;
goto success;
#endif /* CONFIG_64BIT */
/* Cannot handle 64-bit instructions in 32-bit kernel */
goto sigill;
storeHW:
if (!access_ok(VERIFY_WRITE, addr, 2))
goto sigbus;
value = regs->regs[reg];
StoreHW(addr, value, res);
if (res)
goto fault;
goto success;
storeW:
if (!access_ok(VERIFY_WRITE, addr, 4))
goto sigbus;
value = regs->regs[reg];
StoreW(addr, value, res);
if (res)
goto fault;
goto success;
storeDW:
#ifdef CONFIG_64BIT
/*
* A 32-bit kernel might be running on a 64-bit processor. But
* if we're on a 32-bit processor and an i-cache incoherency
* or race makes us see a 64-bit instruction here the sdl/sdr
* would blow up, so for now we don't handle unaligned 64-bit
* instructions on 32-bit kernels.
*/
if (!access_ok(VERIFY_WRITE, addr, 8))
goto sigbus;
value = regs->regs[reg];
StoreDW(addr, value, res);
if (res)
goto fault;
goto success;
#endif /* CONFIG_64BIT */
/* Cannot handle 64-bit instructions in 32-bit kernel */
goto sigill;
success:
regs->cp0_epc = contpc; /* advance or branch */
#ifdef CONFIG_DEBUG_FS
unaligned_instructions++;
#endif
return;
fault:
/* roll back jump/branch */
regs->cp0_epc = origpc;
regs->regs[31] = orig31;
/* Did we have an exception handler installed? */
if (fixup_exception(regs))
return;
die_if_kernel("Unhandled kernel unaligned access", regs);
force_sig(SIGSEGV, current);
return;
sigbus:
die_if_kernel("Unhandled kernel unaligned access", regs);
force_sig(SIGBUS, current);
return;
sigill:
die_if_kernel
("Unhandled kernel unaligned access or invalid instruction", regs);
force_sig(SIGILL, current);
}
static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr)
{
unsigned long value;
unsigned int res;
int reg;
unsigned long orig31;
u16 __user *pc16;
unsigned long origpc;
union mips16e_instruction mips16inst, oldinst;
origpc = regs->cp0_epc;
orig31 = regs->regs[31];
pc16 = (unsigned short __user *)msk_isa16_mode(origpc);
/*
* This load never faults.
*/
__get_user(mips16inst.full, pc16);
oldinst = mips16inst;
/* skip EXTEND instruction */
if (mips16inst.ri.opcode == MIPS16e_extend_op) {
pc16++;
__get_user(mips16inst.full, pc16);
} else if (delay_slot(regs)) {
/* skip jump instructions */
/* JAL/JALX are 32 bits but have OPCODE in first short int */
if (mips16inst.ri.opcode == MIPS16e_jal_op)
pc16++;
pc16++;
if (get_user(mips16inst.full, pc16))
goto sigbus;
}
switch (mips16inst.ri.opcode) {
case MIPS16e_i64_op: /* I64 or RI64 instruction */
switch (mips16inst.i64.func) { /* I64/RI64 func field check */
case MIPS16e_ldpc_func:
case MIPS16e_ldsp_func:
reg = reg16to32[mips16inst.ri64.ry];
goto loadDW;
case MIPS16e_sdsp_func:
reg = reg16to32[mips16inst.ri64.ry];
goto writeDW;
case MIPS16e_sdrasp_func:
reg = 29; /* GPRSP */
goto writeDW;
}
goto sigbus;
case MIPS16e_swsp_op:
case MIPS16e_lwpc_op:
case MIPS16e_lwsp_op:
reg = reg16to32[mips16inst.ri.rx];
break;
case MIPS16e_i8_op:
if (mips16inst.i8.func != MIPS16e_swrasp_func)
goto sigbus;
reg = 29; /* GPRSP */
break;
default:
reg = reg16to32[mips16inst.rri.ry];
break;
}
switch (mips16inst.ri.opcode) {
case MIPS16e_lb_op:
case MIPS16e_lbu_op:
case MIPS16e_sb_op:
goto sigbus;
case MIPS16e_lh_op:
if (!access_ok(VERIFY_READ, addr, 2))
goto sigbus;
LoadHW(addr, value, res);
if (res)
goto fault;
MIPS16e_compute_return_epc(regs, &oldinst);
regs->regs[reg] = value;
break;
case MIPS16e_lhu_op:
if (!access_ok(VERIFY_READ, addr, 2))
goto sigbus;
LoadHWU(addr, value, res);
if (res)
goto fault;
MIPS16e_compute_return_epc(regs, &oldinst);
regs->regs[reg] = value;
break;
case MIPS16e_lw_op:
case MIPS16e_lwpc_op:
case MIPS16e_lwsp_op:
if (!access_ok(VERIFY_READ, addr, 4))
goto sigbus;
LoadW(addr, value, res);
if (res)
goto fault;
MIPS16e_compute_return_epc(regs, &oldinst);
regs->regs[reg] = value;
break;
case MIPS16e_lwu_op:
#ifdef CONFIG_64BIT
/*
* A 32-bit kernel might be running on a 64-bit processor. But
* if we're on a 32-bit processor and an i-cache incoherency
* or race makes us see a 64-bit instruction here the sdl/sdr
* would blow up, so for now we don't handle unaligned 64-bit
* instructions on 32-bit kernels.
*/
if (!access_ok(VERIFY_READ, addr, 4))
goto sigbus;
LoadWU(addr, value, res);
if (res)
goto fault;
MIPS16e_compute_return_epc(regs, &oldinst);
regs->regs[reg] = value;
break;
#endif /* CONFIG_64BIT */
/* Cannot handle 64-bit instructions in 32-bit kernel */
goto sigill;
case MIPS16e_ld_op:
loadDW:
#ifdef CONFIG_64BIT
/*
* A 32-bit kernel might be running on a 64-bit processor. But
* if we're on a 32-bit processor and an i-cache incoherency
* or race makes us see a 64-bit instruction here the sdl/sdr
* would blow up, so for now we don't handle unaligned 64-bit
* instructions on 32-bit kernels.
*/
if (!access_ok(VERIFY_READ, addr, 8))
goto sigbus;
LoadDW(addr, value, res);
if (res)
goto fault;
MIPS16e_compute_return_epc(regs, &oldinst);
regs->regs[reg] = value;
break;
#endif /* CONFIG_64BIT */
/* Cannot handle 64-bit instructions in 32-bit kernel */
goto sigill;
case MIPS16e_sh_op:
if (!access_ok(VERIFY_WRITE, addr, 2))
goto sigbus;
MIPS16e_compute_return_epc(regs, &oldinst);
value = regs->regs[reg];
StoreHW(addr, value, res);
if (res)
goto fault;
break;
case MIPS16e_sw_op:
case MIPS16e_swsp_op:
case MIPS16e_i8_op: /* actually - MIPS16e_swrasp_func */
if (!access_ok(VERIFY_WRITE, addr, 4))
goto sigbus;
MIPS16e_compute_return_epc(regs, &oldinst);
value = regs->regs[reg];
StoreW(addr, value, res);
if (res)
goto fault;
break;
case MIPS16e_sd_op:
writeDW:
#ifdef CONFIG_64BIT
/*
* A 32-bit kernel might be running on a 64-bit processor. But
* if we're on a 32-bit processor and an i-cache incoherency
* or race makes us see a 64-bit instruction here the sdl/sdr
* would blow up, so for now we don't handle unaligned 64-bit
* instructions on 32-bit kernels.
*/
if (!access_ok(VERIFY_WRITE, addr, 8))
goto sigbus;
MIPS16e_compute_return_epc(regs, &oldinst);
value = regs->regs[reg];
StoreDW(addr, value, res);
if (res)
goto fault;
break;
#endif /* CONFIG_64BIT */
/* Cannot handle 64-bit instructions in 32-bit kernel */
goto sigill;
default:
/*
* Pheeee... We encountered an yet unknown instruction or
* cache coherence problem. Die sucker, die ...
*/
goto sigill;
}
#ifdef CONFIG_DEBUG_FS
unaligned_instructions++;
#endif
return;
fault:
/* roll back jump/branch */
regs->cp0_epc = origpc;
regs->regs[31] = orig31;
/* Did we have an exception handler installed? */
if (fixup_exception(regs))
return;
die_if_kernel("Unhandled kernel unaligned access", regs);
force_sig(SIGSEGV, current);
return;
sigbus:
die_if_kernel("Unhandled kernel unaligned access", regs);
force_sig(SIGBUS, current);
return;
sigill:
die_if_kernel
("Unhandled kernel unaligned access or invalid instruction", regs);
force_sig(SIGILL, current);
}
asmlinkage void do_ade(struct pt_regs *regs) asmlinkage void do_ade(struct pt_regs *regs)
{ {
unsigned int __user *pc; unsigned int __user *pc;
...@@ -517,23 +1557,62 @@ asmlinkage void do_ade(struct pt_regs *regs) ...@@ -517,23 +1557,62 @@ asmlinkage void do_ade(struct pt_regs *regs)
1, regs, regs->cp0_badvaddr); 1, regs, regs->cp0_badvaddr);
/* /*
* Did we catch a fault trying to load an instruction? * Did we catch a fault trying to load an instruction?
* Or are we running in MIPS16 mode?
*/ */
if ((regs->cp0_badvaddr == regs->cp0_epc) || (regs->cp0_epc & 0x1)) if (regs->cp0_badvaddr == regs->cp0_epc)
goto sigbus; goto sigbus;
pc = (unsigned int __user *) exception_epc(regs);
if (user_mode(regs) && !test_thread_flag(TIF_FIXADE)) if (user_mode(regs) && !test_thread_flag(TIF_FIXADE))
goto sigbus; goto sigbus;
if (unaligned_action == UNALIGNED_ACTION_SIGNAL) if (unaligned_action == UNALIGNED_ACTION_SIGNAL)
goto sigbus; goto sigbus;
else if (unaligned_action == UNALIGNED_ACTION_SHOW)
show_registers(regs);
/* /*
* Do branch emulation only if we didn't forward the exception. * Do branch emulation only if we didn't forward the exception.
* This is all so but ugly ... * This is all so but ugly ...
*/ */
/*
* Are we running in microMIPS mode?
*/
if (get_isa16_mode(regs->cp0_epc)) {
/*
* Did we catch a fault trying to load an instruction in
* 16-bit mode?
*/
if (regs->cp0_badvaddr == msk_isa16_mode(regs->cp0_epc))
goto sigbus;
if (unaligned_action == UNALIGNED_ACTION_SHOW)
show_registers(regs);
if (cpu_has_mmips) {
seg = get_fs();
if (!user_mode(regs))
set_fs(KERNEL_DS);
emulate_load_store_microMIPS(regs,
(void __user *)regs->cp0_badvaddr);
set_fs(seg);
return;
}
if (cpu_has_mips16) {
seg = get_fs();
if (!user_mode(regs))
set_fs(KERNEL_DS);
emulate_load_store_MIPS16e(regs,
(void __user *)regs->cp0_badvaddr);
set_fs(seg);
return;
}
goto sigbus;
}
if (unaligned_action == UNALIGNED_ACTION_SHOW)
show_registers(regs);
pc = (unsigned int __user *)exception_epc(regs);
seg = get_fs(); seg = get_fs();
if (!user_mode(regs)) if (!user_mode(regs))
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
......
...@@ -525,18 +525,16 @@ kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc, uint32_t cause, ...@@ -525,18 +525,16 @@ kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc, uint32_t cause,
printk("MTCz, cop0->reg[EBASE]: %#lx\n", printk("MTCz, cop0->reg[EBASE]: %#lx\n",
kvm_read_c0_guest_ebase(cop0)); kvm_read_c0_guest_ebase(cop0));
} else if (rd == MIPS_CP0_TLB_HI && sel == 0) { } else if (rd == MIPS_CP0_TLB_HI && sel == 0) {
uint32_t nasid = uint32_t nasid = ASID_MASK(vcpu->arch.gprs[rt]);
vcpu->arch.gprs[rt] & ASID_MASK;
if ((KSEGX(vcpu->arch.gprs[rt]) != CKSEG0) if ((KSEGX(vcpu->arch.gprs[rt]) != CKSEG0)
&& &&
((kvm_read_c0_guest_entryhi(cop0) & (ASID_MASK(kvm_read_c0_guest_entryhi(cop0))
ASID_MASK) != nasid)) { != nasid)) {
kvm_debug kvm_debug
("MTCz, change ASID from %#lx to %#lx\n", ("MTCz, change ASID from %#lx to %#lx\n",
kvm_read_c0_guest_entryhi(cop0) & ASID_MASK(kvm_read_c0_guest_entryhi(cop0)),
ASID_MASK, ASID_MASK(vcpu->arch.gprs[rt]));
vcpu->arch.gprs[rt] & ASID_MASK);
/* Blow away the shadow host TLBs */ /* Blow away the shadow host TLBs */
kvm_mips_flush_host_tlb(1); kvm_mips_flush_host_tlb(1);
...@@ -988,8 +986,7 @@ kvm_mips_emulate_cache(uint32_t inst, uint32_t *opc, uint32_t cause, ...@@ -988,8 +986,7 @@ kvm_mips_emulate_cache(uint32_t inst, uint32_t *opc, uint32_t cause,
* resulting handler will do the right thing * resulting handler will do the right thing
*/ */
index = kvm_mips_guest_tlb_lookup(vcpu, (va & VPN2_MASK) | index = kvm_mips_guest_tlb_lookup(vcpu, (va & VPN2_MASK) |
(kvm_read_c0_guest_entryhi ASID_MASK(kvm_read_c0_guest_entryhi(cop0)));
(cop0) & ASID_MASK));
if (index < 0) { if (index < 0) {
vcpu->arch.host_cp0_entryhi = (va & VPN2_MASK); vcpu->arch.host_cp0_entryhi = (va & VPN2_MASK);
...@@ -1154,7 +1151,7 @@ kvm_mips_emulate_tlbmiss_ld(unsigned long cause, uint32_t *opc, ...@@ -1154,7 +1151,7 @@ kvm_mips_emulate_tlbmiss_ld(unsigned long cause, uint32_t *opc,
struct kvm_vcpu_arch *arch = &vcpu->arch; struct kvm_vcpu_arch *arch = &vcpu->arch;
enum emulation_result er = EMULATE_DONE; enum emulation_result er = EMULATE_DONE;
unsigned long entryhi = (vcpu->arch. host_cp0_badvaddr & VPN2_MASK) | unsigned long entryhi = (vcpu->arch. host_cp0_badvaddr & VPN2_MASK) |
(kvm_read_c0_guest_entryhi(cop0) & ASID_MASK); ASID_MASK(kvm_read_c0_guest_entryhi(cop0));
if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) { if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) {
/* save old pc */ /* save old pc */
...@@ -1201,7 +1198,7 @@ kvm_mips_emulate_tlbinv_ld(unsigned long cause, uint32_t *opc, ...@@ -1201,7 +1198,7 @@ kvm_mips_emulate_tlbinv_ld(unsigned long cause, uint32_t *opc,
enum emulation_result er = EMULATE_DONE; enum emulation_result er = EMULATE_DONE;
unsigned long entryhi = unsigned long entryhi =
(vcpu->arch.host_cp0_badvaddr & VPN2_MASK) | (vcpu->arch.host_cp0_badvaddr & VPN2_MASK) |
(kvm_read_c0_guest_entryhi(cop0) & ASID_MASK); ASID_MASK(kvm_read_c0_guest_entryhi(cop0));
if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) { if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) {
/* save old pc */ /* save old pc */
...@@ -1246,7 +1243,7 @@ kvm_mips_emulate_tlbmiss_st(unsigned long cause, uint32_t *opc, ...@@ -1246,7 +1243,7 @@ kvm_mips_emulate_tlbmiss_st(unsigned long cause, uint32_t *opc,
struct kvm_vcpu_arch *arch = &vcpu->arch; struct kvm_vcpu_arch *arch = &vcpu->arch;
enum emulation_result er = EMULATE_DONE; enum emulation_result er = EMULATE_DONE;
unsigned long entryhi = (vcpu->arch.host_cp0_badvaddr & VPN2_MASK) | unsigned long entryhi = (vcpu->arch.host_cp0_badvaddr & VPN2_MASK) |
(kvm_read_c0_guest_entryhi(cop0) & ASID_MASK); ASID_MASK(kvm_read_c0_guest_entryhi(cop0));
if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) { if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) {
/* save old pc */ /* save old pc */
...@@ -1290,7 +1287,7 @@ kvm_mips_emulate_tlbinv_st(unsigned long cause, uint32_t *opc, ...@@ -1290,7 +1287,7 @@ kvm_mips_emulate_tlbinv_st(unsigned long cause, uint32_t *opc,
struct kvm_vcpu_arch *arch = &vcpu->arch; struct kvm_vcpu_arch *arch = &vcpu->arch;
enum emulation_result er = EMULATE_DONE; enum emulation_result er = EMULATE_DONE;
unsigned long entryhi = (vcpu->arch.host_cp0_badvaddr & VPN2_MASK) | unsigned long entryhi = (vcpu->arch.host_cp0_badvaddr & VPN2_MASK) |
(kvm_read_c0_guest_entryhi(cop0) & ASID_MASK); ASID_MASK(kvm_read_c0_guest_entryhi(cop0));
if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) { if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) {
/* save old pc */ /* save old pc */
...@@ -1359,7 +1356,7 @@ kvm_mips_emulate_tlbmod(unsigned long cause, uint32_t *opc, ...@@ -1359,7 +1356,7 @@ kvm_mips_emulate_tlbmod(unsigned long cause, uint32_t *opc,
{ {
struct mips_coproc *cop0 = vcpu->arch.cop0; struct mips_coproc *cop0 = vcpu->arch.cop0;
unsigned long entryhi = (vcpu->arch.host_cp0_badvaddr & VPN2_MASK) | unsigned long entryhi = (vcpu->arch.host_cp0_badvaddr & VPN2_MASK) |
(kvm_read_c0_guest_entryhi(cop0) & ASID_MASK); ASID_MASK(kvm_read_c0_guest_entryhi(cop0));
struct kvm_vcpu_arch *arch = &vcpu->arch; struct kvm_vcpu_arch *arch = &vcpu->arch;
enum emulation_result er = EMULATE_DONE; enum emulation_result er = EMULATE_DONE;
...@@ -1786,8 +1783,8 @@ kvm_mips_handle_tlbmiss(unsigned long cause, uint32_t *opc, ...@@ -1786,8 +1783,8 @@ kvm_mips_handle_tlbmiss(unsigned long cause, uint32_t *opc,
*/ */
index = kvm_mips_guest_tlb_lookup(vcpu, index = kvm_mips_guest_tlb_lookup(vcpu,
(va & VPN2_MASK) | (va & VPN2_MASK) |
(kvm_read_c0_guest_entryhi ASID_MASK(kvm_read_c0_guest_entryhi
(vcpu->arch.cop0) & ASID_MASK)); (vcpu->arch.cop0)));
if (index < 0) { if (index < 0) {
if (exccode == T_TLB_LD_MISS) { if (exccode == T_TLB_LD_MISS) {
er = kvm_mips_emulate_tlbmiss_ld(cause, opc, run, vcpu); er = kvm_mips_emulate_tlbmiss_ld(cause, opc, run, vcpu);
......
...@@ -51,13 +51,13 @@ EXPORT_SYMBOL(kvm_mips_is_error_pfn); ...@@ -51,13 +51,13 @@ EXPORT_SYMBOL(kvm_mips_is_error_pfn);
uint32_t kvm_mips_get_kernel_asid(struct kvm_vcpu *vcpu) uint32_t kvm_mips_get_kernel_asid(struct kvm_vcpu *vcpu)
{ {
return vcpu->arch.guest_kernel_asid[smp_processor_id()] & ASID_MASK; return ASID_MASK(vcpu->arch.guest_kernel_asid[smp_processor_id()]);
} }
uint32_t kvm_mips_get_user_asid(struct kvm_vcpu *vcpu) uint32_t kvm_mips_get_user_asid(struct kvm_vcpu *vcpu)
{ {
return vcpu->arch.guest_user_asid[smp_processor_id()] & ASID_MASK; return ASID_MASK(vcpu->arch.guest_user_asid[smp_processor_id()]);
} }
inline uint32_t kvm_mips_get_commpage_asid (struct kvm_vcpu *vcpu) inline uint32_t kvm_mips_get_commpage_asid (struct kvm_vcpu *vcpu)
...@@ -84,7 +84,7 @@ void kvm_mips_dump_host_tlbs(void) ...@@ -84,7 +84,7 @@ void kvm_mips_dump_host_tlbs(void)
old_pagemask = read_c0_pagemask(); old_pagemask = read_c0_pagemask();
printk("HOST TLBs:\n"); printk("HOST TLBs:\n");
printk("ASID: %#lx\n", read_c0_entryhi() & ASID_MASK); printk("ASID: %#lx\n", ASID_MASK(read_c0_entryhi()));
for (i = 0; i < current_cpu_data.tlbsize; i++) { for (i = 0; i < current_cpu_data.tlbsize; i++) {
write_c0_index(i); write_c0_index(i);
...@@ -428,7 +428,7 @@ int kvm_mips_guest_tlb_lookup(struct kvm_vcpu *vcpu, unsigned long entryhi) ...@@ -428,7 +428,7 @@ int kvm_mips_guest_tlb_lookup(struct kvm_vcpu *vcpu, unsigned long entryhi)
for (i = 0; i < KVM_MIPS_GUEST_TLB_SIZE; i++) { for (i = 0; i < KVM_MIPS_GUEST_TLB_SIZE; i++) {
if (((TLB_VPN2(tlb[i]) & ~tlb[i].tlb_mask) == ((entryhi & VPN2_MASK) & ~tlb[i].tlb_mask)) && if (((TLB_VPN2(tlb[i]) & ~tlb[i].tlb_mask) == ((entryhi & VPN2_MASK) & ~tlb[i].tlb_mask)) &&
(TLB_IS_GLOBAL(tlb[i]) || (TLB_ASID(tlb[i]) == (entryhi & ASID_MASK)))) { (TLB_IS_GLOBAL(tlb[i]) || (TLB_ASID(tlb[i]) == ASID_MASK(entryhi)))) {
index = i; index = i;
break; break;
} }
...@@ -626,7 +626,7 @@ kvm_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu, ...@@ -626,7 +626,7 @@ kvm_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu,
{ {
unsigned long asid = asid_cache(cpu); unsigned long asid = asid_cache(cpu);
if (!((asid += ASID_INC) & ASID_MASK)) { if (!(ASID_MASK(ASID_INC(asid)))) {
if (cpu_has_vtag_icache) { if (cpu_has_vtag_icache) {
flush_icache_all(); flush_icache_all();
} }
...@@ -804,8 +804,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) ...@@ -804,8 +804,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
if (!newasid) { if (!newasid) {
/* If we preempted while the guest was executing, then reload the pre-empted ASID */ /* If we preempted while the guest was executing, then reload the pre-empted ASID */
if (current->flags & PF_VCPU) { if (current->flags & PF_VCPU) {
write_c0_entryhi(vcpu->arch. write_c0_entryhi(ASID_MASK(vcpu->arch.preempt_entryhi));
preempt_entryhi & ASID_MASK);
ehb(); ehb();
} }
} else { } else {
...@@ -817,13 +816,11 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) ...@@ -817,13 +816,11 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
*/ */
if (current->flags & PF_VCPU) { if (current->flags & PF_VCPU) {
if (KVM_GUEST_KERNEL_MODE(vcpu)) if (KVM_GUEST_KERNEL_MODE(vcpu))
write_c0_entryhi(vcpu->arch. write_c0_entryhi(ASID_MASK(vcpu->arch.
guest_kernel_asid[cpu] & guest_kernel_asid[cpu]));
ASID_MASK);
else else
write_c0_entryhi(vcpu->arch. write_c0_entryhi(ASID_MASK(vcpu->arch.
guest_user_asid[cpu] & guest_user_asid[cpu]));
ASID_MASK);
ehb(); ehb();
} }
} }
...@@ -882,8 +879,7 @@ uint32_t kvm_get_inst(uint32_t *opc, struct kvm_vcpu *vcpu) ...@@ -882,8 +879,7 @@ uint32_t kvm_get_inst(uint32_t *opc, struct kvm_vcpu *vcpu)
kvm_mips_guest_tlb_lookup(vcpu, kvm_mips_guest_tlb_lookup(vcpu,
((unsigned long) opc & VPN2_MASK) ((unsigned long) opc & VPN2_MASK)
| |
(kvm_read_c0_guest_entryhi ASID_MASK(kvm_read_c0_guest_entryhi(cop0)));
(cop0) & ASID_MASK));
if (index < 0) { if (index < 0) {
kvm_err kvm_err
("%s: get_user_failed for %p, vcpu: %p, ASID: %#lx\n", ("%s: get_user_failed for %p, vcpu: %p, ASID: %#lx\n",
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <asm/page.h> #include <asm/page.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/tlbdebug.h> #include <asm/tlbdebug.h>
#include <asm/mmu_context.h>
static inline const char *msk2str(unsigned int mask) static inline const char *msk2str(unsigned int mask)
{ {
...@@ -55,7 +56,7 @@ static void dump_tlb(int first, int last) ...@@ -55,7 +56,7 @@ static void dump_tlb(int first, int last)
s_pagemask = read_c0_pagemask(); s_pagemask = read_c0_pagemask();
s_entryhi = read_c0_entryhi(); s_entryhi = read_c0_entryhi();
s_index = read_c0_index(); s_index = read_c0_index();
asid = s_entryhi & 0xff; asid = ASID_MASK(s_entryhi);
for (i = first; i <= last; i++) { for (i = first; i <= last; i++) {
write_c0_index(i); write_c0_index(i);
...@@ -85,7 +86,7 @@ static void dump_tlb(int first, int last) ...@@ -85,7 +86,7 @@ static void dump_tlb(int first, int last)
printk("va=%0*lx asid=%02lx\n", printk("va=%0*lx asid=%02lx\n",
width, (entryhi & ~0x1fffUL), width, (entryhi & ~0x1fffUL),
entryhi & 0xff); ASID_MASK(entryhi));
printk("\t[pa=%0*llx c=%d d=%d v=%d g=%d] ", printk("\t[pa=%0*llx c=%d d=%d v=%d g=%d] ",
width, width,
(entrylo0 << 6) & PAGE_MASK, c0, (entrylo0 << 6) & PAGE_MASK, c0,
......
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
* *
* Copyright (C) 1998, 1999, 2000 by Ralf Baechle * Copyright (C) 1998, 1999, 2000 by Ralf Baechle
* Copyright (C) 1999, 2000 Silicon Graphics, Inc. * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
* Copyright (C) 2007 Maciej W. Rozycki * Copyright (C) 2007 by Maciej W. Rozycki
* Copyright (C) 2011, 2012 MIPS Technologies, Inc.
*/ */
#include <asm/asm.h> #include <asm/asm.h>
#include <asm/asm-offsets.h> #include <asm/asm-offsets.h>
...@@ -19,6 +20,20 @@ ...@@ -19,6 +20,20 @@
#define LONG_S_R sdr #define LONG_S_R sdr
#endif #endif
#ifdef CONFIG_CPU_MICROMIPS
#define STORSIZE (LONGSIZE * 2)
#define STORMASK (STORSIZE - 1)
#define FILL64RG t8
#define FILLPTRG t7
#undef LONG_S
#define LONG_S LONG_SP
#else
#define STORSIZE LONGSIZE
#define STORMASK LONGMASK
#define FILL64RG a1
#define FILLPTRG t0
#endif
#define EX(insn,reg,addr,handler) \ #define EX(insn,reg,addr,handler) \
9: insn reg, addr; \ 9: insn reg, addr; \
.section __ex_table,"a"; \ .section __ex_table,"a"; \
...@@ -26,23 +41,25 @@ ...@@ -26,23 +41,25 @@
.previous .previous
.macro f_fill64 dst, offset, val, fixup .macro f_fill64 dst, offset, val, fixup
EX(LONG_S, \val, (\offset + 0 * LONGSIZE)(\dst), \fixup) EX(LONG_S, \val, (\offset + 0 * STORSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 1 * LONGSIZE)(\dst), \fixup) EX(LONG_S, \val, (\offset + 1 * STORSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 2 * LONGSIZE)(\dst), \fixup) EX(LONG_S, \val, (\offset + 2 * STORSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 3 * LONGSIZE)(\dst), \fixup) EX(LONG_S, \val, (\offset + 3 * STORSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 4 * LONGSIZE)(\dst), \fixup) #if ((defined(CONFIG_CPU_MICROMIPS) && (LONGSIZE == 4)) || !defined(CONFIG_CPU_MICROMIPS))
EX(LONG_S, \val, (\offset + 5 * LONGSIZE)(\dst), \fixup) EX(LONG_S, \val, (\offset + 4 * STORSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 6 * LONGSIZE)(\dst), \fixup) EX(LONG_S, \val, (\offset + 5 * STORSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 7 * LONGSIZE)(\dst), \fixup) EX(LONG_S, \val, (\offset + 6 * STORSIZE)(\dst), \fixup)
#if LONGSIZE == 4 EX(LONG_S, \val, (\offset + 7 * STORSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 8 * LONGSIZE)(\dst), \fixup) #endif
EX(LONG_S, \val, (\offset + 9 * LONGSIZE)(\dst), \fixup) #if (!defined(CONFIG_CPU_MICROMIPS) && (LONGSIZE == 4))
EX(LONG_S, \val, (\offset + 10 * LONGSIZE)(\dst), \fixup) EX(LONG_S, \val, (\offset + 8 * STORSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 11 * LONGSIZE)(\dst), \fixup) EX(LONG_S, \val, (\offset + 9 * STORSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 12 * LONGSIZE)(\dst), \fixup) EX(LONG_S, \val, (\offset + 10 * STORSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 13 * LONGSIZE)(\dst), \fixup) EX(LONG_S, \val, (\offset + 11 * STORSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 14 * LONGSIZE)(\dst), \fixup) EX(LONG_S, \val, (\offset + 12 * STORSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 15 * LONGSIZE)(\dst), \fixup) EX(LONG_S, \val, (\offset + 13 * STORSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 14 * STORSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 15 * STORSIZE)(\dst), \fixup)
#endif #endif
.endm .endm
...@@ -71,16 +88,20 @@ LEAF(memset) ...@@ -71,16 +88,20 @@ LEAF(memset)
1: 1:
FEXPORT(__bzero) FEXPORT(__bzero)
sltiu t0, a2, LONGSIZE /* very small region? */ sltiu t0, a2, STORSIZE /* very small region? */
bnez t0, .Lsmall_memset bnez t0, .Lsmall_memset
andi t0, a0, LONGMASK /* aligned? */ andi t0, a0, STORMASK /* aligned? */
#ifdef CONFIG_CPU_MICROMIPS
move t8, a1 /* used by 'swp' instruction */
move t9, a1
#endif
#ifndef CONFIG_CPU_DADDI_WORKAROUNDS #ifndef CONFIG_CPU_DADDI_WORKAROUNDS
beqz t0, 1f beqz t0, 1f
PTR_SUBU t0, LONGSIZE /* alignment in bytes */ PTR_SUBU t0, STORSIZE /* alignment in bytes */
#else #else
.set noat .set noat
li AT, LONGSIZE li AT, STORSIZE
beqz t0, 1f beqz t0, 1f
PTR_SUBU t0, AT /* alignment in bytes */ PTR_SUBU t0, AT /* alignment in bytes */
.set at .set at
...@@ -99,24 +120,27 @@ FEXPORT(__bzero) ...@@ -99,24 +120,27 @@ FEXPORT(__bzero)
1: ori t1, a2, 0x3f /* # of full blocks */ 1: ori t1, a2, 0x3f /* # of full blocks */
xori t1, 0x3f xori t1, 0x3f
beqz t1, .Lmemset_partial /* no block to fill */ beqz t1, .Lmemset_partial /* no block to fill */
andi t0, a2, 0x40-LONGSIZE andi t0, a2, 0x40-STORSIZE
PTR_ADDU t1, a0 /* end address */ PTR_ADDU t1, a0 /* end address */
.set reorder .set reorder
1: PTR_ADDIU a0, 64 1: PTR_ADDIU a0, 64
R10KCBARRIER(0(ra)) R10KCBARRIER(0(ra))
f_fill64 a0, -64, a1, .Lfwd_fixup f_fill64 a0, -64, FILL64RG, .Lfwd_fixup
bne t1, a0, 1b bne t1, a0, 1b
.set noreorder .set noreorder
.Lmemset_partial: .Lmemset_partial:
R10KCBARRIER(0(ra)) R10KCBARRIER(0(ra))
PTR_LA t1, 2f /* where to start */ PTR_LA t1, 2f /* where to start */
#ifdef CONFIG_CPU_MICROMIPS
LONG_SRL t7, t0, 1
#endif
#if LONGSIZE == 4 #if LONGSIZE == 4
PTR_SUBU t1, t0 PTR_SUBU t1, FILLPTRG
#else #else
.set noat .set noat
LONG_SRL AT, t0, 1 LONG_SRL AT, FILLPTRG, 1
PTR_SUBU t1, AT PTR_SUBU t1, AT
.set at .set at
#endif #endif
...@@ -126,9 +150,9 @@ FEXPORT(__bzero) ...@@ -126,9 +150,9 @@ FEXPORT(__bzero)
.set push .set push
.set noreorder .set noreorder
.set nomacro .set nomacro
f_fill64 a0, -64, a1, .Lpartial_fixup /* ... but first do longs ... */ f_fill64 a0, -64, FILL64RG, .Lpartial_fixup /* ... but first do longs ... */
2: .set pop 2: .set pop
andi a2, LONGMASK /* At most one long to go */ andi a2, STORMASK /* At most one long to go */
beqz a2, 1f beqz a2, 1f
PTR_ADDU a0, a2 /* What's left */ PTR_ADDU a0, a2 /* What's left */
...@@ -169,7 +193,7 @@ FEXPORT(__bzero) ...@@ -169,7 +193,7 @@ FEXPORT(__bzero)
.Lpartial_fixup: .Lpartial_fixup:
PTR_L t0, TI_TASK($28) PTR_L t0, TI_TASK($28)
andi a2, LONGMASK andi a2, STORMASK
LONG_L t0, THREAD_BUADDR(t0) LONG_L t0, THREAD_BUADDR(t0)
LONG_ADDU a2, t1 LONG_ADDU a2, t1
jr ra jr ra
...@@ -177,4 +201,4 @@ FEXPORT(__bzero) ...@@ -177,4 +201,4 @@ FEXPORT(__bzero)
.Llast_fixup: .Llast_fixup:
jr ra jr ra
andi v1, a2, LONGMASK andi v1, a2, STORMASK
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <asm/mipsregs.h> #include <asm/mipsregs.h>
#include <asm/mmu_context.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/tlbdebug.h> #include <asm/tlbdebug.h>
...@@ -21,7 +22,7 @@ static void dump_tlb(int first, int last) ...@@ -21,7 +22,7 @@ static void dump_tlb(int first, int last)
unsigned int asid; unsigned int asid;
unsigned long entryhi, entrylo0; unsigned long entryhi, entrylo0;
asid = read_c0_entryhi() & 0xfc0; asid = ASID_MASK(read_c0_entryhi());
for (i = first; i <= last; i++) { for (i = first; i <= last; i++) {
write_c0_index(i<<8); write_c0_index(i<<8);
...@@ -35,7 +36,7 @@ static void dump_tlb(int first, int last) ...@@ -35,7 +36,7 @@ static void dump_tlb(int first, int last)
/* Unused entries have a virtual address of KSEG0. */ /* Unused entries have a virtual address of KSEG0. */
if ((entryhi & 0xffffe000) != 0x80000000 if ((entryhi & 0xffffe000) != 0x80000000
&& (entryhi & 0xfc0) == asid) { && (ASID_MASK(entryhi) == asid)) {
/* /*
* Only print entries in use * Only print entries in use
*/ */
...@@ -44,7 +45,7 @@ static void dump_tlb(int first, int last) ...@@ -44,7 +45,7 @@ static void dump_tlb(int first, int last)
printk("va=%08lx asid=%08lx" printk("va=%08lx asid=%08lx"
" [pa=%06lx n=%d d=%d v=%d g=%d]", " [pa=%06lx n=%d d=%d v=%d g=%d]",
(entryhi & 0xffffe000), (entryhi & 0xffffe000),
entryhi & 0xfc0, ASID_MASK(entryhi),
entrylo0 & PAGE_MASK, entrylo0 & PAGE_MASK,
(entrylo0 & (1 << 11)) ? 1 : 0, (entrylo0 & (1 << 11)) ? 1 : 0,
(entrylo0 & (1 << 10)) ? 1 : 0, (entrylo0 & (1 << 10)) ? 1 : 0,
......
...@@ -3,8 +3,9 @@ ...@@ -3,8 +3,9 @@
* License. See the file "COPYING" in the main directory of this archive * License. See the file "COPYING" in the main directory of this archive
* for more details. * for more details.
* *
* Copyright (c) 1996, 1998, 1999, 2004 by Ralf Baechle * Copyright (C) 1996, 1998, 1999, 2004 by Ralf Baechle
* Copyright (c) 1999 Silicon Graphics, Inc. * Copyright (C) 1999 Silicon Graphics, Inc.
* Copyright (C) 2011 MIPS Technologies, Inc.
*/ */
#include <asm/asm.h> #include <asm/asm.h>
#include <asm/asm-offsets.h> #include <asm/asm-offsets.h>
...@@ -28,9 +29,9 @@ LEAF(__strlen_user_asm) ...@@ -28,9 +29,9 @@ LEAF(__strlen_user_asm)
FEXPORT(__strlen_user_nocheck_asm) FEXPORT(__strlen_user_nocheck_asm)
move v0, a0 move v0, a0
1: EX(lb, t0, (v0), .Lfault) 1: EX(lbu, v1, (v0), .Lfault)
PTR_ADDIU v0, 1 PTR_ADDIU v0, 1
bnez t0, 1b bnez v1, 1b
PTR_SUBU v0, a0 PTR_SUBU v0, a0
jr ra jr ra
END(__strlen_user_asm) END(__strlen_user_asm)
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
* License. See the file "COPYING" in the main directory of this archive * License. See the file "COPYING" in the main directory of this archive
* for more details. * for more details.
* *
* Copyright (c) 1996, 1999 by Ralf Baechle * Copyright (C) 1996, 1999 by Ralf Baechle
* Copyright (C) 2011 MIPS Technologies, Inc.
*/ */
#include <linux/errno.h> #include <linux/errno.h>
#include <asm/asm.h> #include <asm/asm.h>
...@@ -33,26 +34,27 @@ LEAF(__strncpy_from_user_asm) ...@@ -33,26 +34,27 @@ LEAF(__strncpy_from_user_asm)
bnez v0, .Lfault bnez v0, .Lfault
FEXPORT(__strncpy_from_user_nocheck_asm) FEXPORT(__strncpy_from_user_nocheck_asm)
move v0, zero
move v1, a1
.set noreorder .set noreorder
1: EX(lbu, t0, (v1), .Lfault) move t0, zero
move v1, a1
1: EX(lbu, v0, (v1), .Lfault)
PTR_ADDIU v1, 1 PTR_ADDIU v1, 1
R10KCBARRIER(0(ra)) R10KCBARRIER(0(ra))
beqz t0, 2f beqz v0, 2f
sb t0, (a0) sb v0, (a0)
PTR_ADDIU v0, 1 PTR_ADDIU t0, 1
.set reorder bne t0, a2, 1b
PTR_ADDIU a0, 1 PTR_ADDIU a0, 1
bne v0, a2, 1b 2: PTR_ADDU v0, a1, t0
2: PTR_ADDU t0, a1, v0 xor v0, a1
xor t0, a1 bltz v0, .Lfault
bltz t0, .Lfault nop
jr ra # return n jr ra # return n
move v0, t0
END(__strncpy_from_user_asm) END(__strncpy_from_user_asm)
.Lfault: li v0, -EFAULT .Lfault: jr ra
jr ra li v0, -EFAULT
.section __ex_table,"a" .section __ex_table,"a"
PTR 1b, .Lfault PTR 1b, .Lfault
......
...@@ -35,7 +35,7 @@ FEXPORT(__strnlen_user_nocheck_asm) ...@@ -35,7 +35,7 @@ FEXPORT(__strnlen_user_nocheck_asm)
PTR_ADDU a1, a0 # stop pointer PTR_ADDU a1, a0 # stop pointer
1: beq v0, a1, 1f # limit reached? 1: beq v0, a1, 1f # limit reached?
EX(lb, t0, (v0), .Lfault) EX(lb, t0, (v0), .Lfault)
PTR_ADDU v0, 1 PTR_ADDIU v0, 1
bnez t0, 1b bnez t0, 1b
1: PTR_SUBU v0, a0 1: PTR_SUBU v0, a0
jr ra jr ra
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#include <asm/signal.h> #include <asm/signal.h>
#include <asm/mipsregs.h> #include <asm/mipsregs.h>
#include <asm/fpu_emulator.h> #include <asm/fpu_emulator.h>
#include <asm/fpu.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/branch.h> #include <asm/branch.h>
...@@ -81,6 +82,11 @@ DEFINE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats); ...@@ -81,6 +82,11 @@ DEFINE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats);
/* Determine rounding mode from the RM bits of the FCSR */ /* Determine rounding mode from the RM bits of the FCSR */
#define modeindex(v) ((v) & FPU_CSR_RM) #define modeindex(v) ((v) & FPU_CSR_RM)
/* microMIPS bitfields */
#define MM_POOL32A_MINOR_MASK 0x3f
#define MM_POOL32A_MINOR_SHIFT 0x6
#define MM_MIPS32_COND_FC 0x30
/* Convert Mips rounding mode (0..3) to IEEE library modes. */ /* Convert Mips rounding mode (0..3) to IEEE library modes. */
static const unsigned char ieee_rm[4] = { static const unsigned char ieee_rm[4] = {
[FPU_CSR_RN] = IEEE754_RN, [FPU_CSR_RN] = IEEE754_RN,
...@@ -110,6 +116,556 @@ static const unsigned int fpucondbit[8] = { ...@@ -110,6 +116,556 @@ static const unsigned int fpucondbit[8] = {
}; };
#endif #endif
/* (microMIPS) Convert 16-bit register encoding to 32-bit register encoding. */
static const unsigned int reg16to32map[8] = {16, 17, 2, 3, 4, 5, 6, 7};
/* (microMIPS) Convert certain microMIPS instructions to MIPS32 format. */
static const int sd_format[] = {16, 17, 0, 0, 0, 0, 0, 0};
static const int sdps_format[] = {16, 17, 22, 0, 0, 0, 0, 0};
static const int dwl_format[] = {17, 20, 21, 0, 0, 0, 0, 0};
static const int swl_format[] = {16, 20, 21, 0, 0, 0, 0, 0};
/*
* This functions translates a 32-bit microMIPS instruction
* into a 32-bit MIPS32 instruction. Returns 0 on success
* and SIGILL otherwise.
*/
static int microMIPS32_to_MIPS32(union mips_instruction *insn_ptr)
{
union mips_instruction insn = *insn_ptr;
union mips_instruction mips32_insn = insn;
int func, fmt, op;
switch (insn.mm_i_format.opcode) {
case mm_ldc132_op:
mips32_insn.mm_i_format.opcode = ldc1_op;
mips32_insn.mm_i_format.rt = insn.mm_i_format.rs;
mips32_insn.mm_i_format.rs = insn.mm_i_format.rt;
break;
case mm_lwc132_op:
mips32_insn.mm_i_format.opcode = lwc1_op;
mips32_insn.mm_i_format.rt = insn.mm_i_format.rs;
mips32_insn.mm_i_format.rs = insn.mm_i_format.rt;
break;
case mm_sdc132_op:
mips32_insn.mm_i_format.opcode = sdc1_op;
mips32_insn.mm_i_format.rt = insn.mm_i_format.rs;
mips32_insn.mm_i_format.rs = insn.mm_i_format.rt;
break;
case mm_swc132_op:
mips32_insn.mm_i_format.opcode = swc1_op;
mips32_insn.mm_i_format.rt = insn.mm_i_format.rs;
mips32_insn.mm_i_format.rs = insn.mm_i_format.rt;
break;
case mm_pool32i_op:
/* NOTE: offset is << by 1 if in microMIPS mode. */
if ((insn.mm_i_format.rt == mm_bc1f_op) ||
(insn.mm_i_format.rt == mm_bc1t_op)) {
mips32_insn.fb_format.opcode = cop1_op;
mips32_insn.fb_format.bc = bc_op;
mips32_insn.fb_format.flag =
(insn.mm_i_format.rt == mm_bc1t_op) ? 1 : 0;
} else
return SIGILL;
break;
case mm_pool32f_op:
switch (insn.mm_fp0_format.func) {
case mm_32f_01_op:
case mm_32f_11_op:
case mm_32f_02_op:
case mm_32f_12_op:
case mm_32f_41_op:
case mm_32f_51_op:
case mm_32f_42_op:
case mm_32f_52_op:
op = insn.mm_fp0_format.func;
if (op == mm_32f_01_op)
func = madd_s_op;
else if (op == mm_32f_11_op)
func = madd_d_op;
else if (op == mm_32f_02_op)
func = nmadd_s_op;
else if (op == mm_32f_12_op)
func = nmadd_d_op;
else if (op == mm_32f_41_op)
func = msub_s_op;
else if (op == mm_32f_51_op)
func = msub_d_op;
else if (op == mm_32f_42_op)
func = nmsub_s_op;
else
func = nmsub_d_op;
mips32_insn.fp6_format.opcode = cop1x_op;
mips32_insn.fp6_format.fr = insn.mm_fp6_format.fr;
mips32_insn.fp6_format.ft = insn.mm_fp6_format.ft;
mips32_insn.fp6_format.fs = insn.mm_fp6_format.fs;
mips32_insn.fp6_format.fd = insn.mm_fp6_format.fd;
mips32_insn.fp6_format.func = func;
break;
case mm_32f_10_op:
func = -1; /* Invalid */
op = insn.mm_fp5_format.op & 0x7;
if (op == mm_ldxc1_op)
func = ldxc1_op;
else if (op == mm_sdxc1_op)
func = sdxc1_op;
else if (op == mm_lwxc1_op)
func = lwxc1_op;
else if (op == mm_swxc1_op)
func = swxc1_op;
if (func != -1) {
mips32_insn.r_format.opcode = cop1x_op;
mips32_insn.r_format.rs =
insn.mm_fp5_format.base;
mips32_insn.r_format.rt =
insn.mm_fp5_format.index;
mips32_insn.r_format.rd = 0;
mips32_insn.r_format.re = insn.mm_fp5_format.fd;
mips32_insn.r_format.func = func;
} else
return SIGILL;
break;
case mm_32f_40_op:
op = -1; /* Invalid */
if (insn.mm_fp2_format.op == mm_fmovt_op)
op = 1;
else if (insn.mm_fp2_format.op == mm_fmovf_op)
op = 0;
if (op != -1) {
mips32_insn.fp0_format.opcode = cop1_op;
mips32_insn.fp0_format.fmt =
sdps_format[insn.mm_fp2_format.fmt];
mips32_insn.fp0_format.ft =
(insn.mm_fp2_format.cc<<2) + op;
mips32_insn.fp0_format.fs =
insn.mm_fp2_format.fs;
mips32_insn.fp0_format.fd =
insn.mm_fp2_format.fd;
mips32_insn.fp0_format.func = fmovc_op;
} else
return SIGILL;
break;
case mm_32f_60_op:
func = -1; /* Invalid */
if (insn.mm_fp0_format.op == mm_fadd_op)
func = fadd_op;
else if (insn.mm_fp0_format.op == mm_fsub_op)
func = fsub_op;
else if (insn.mm_fp0_format.op == mm_fmul_op)
func = fmul_op;
else if (insn.mm_fp0_format.op == mm_fdiv_op)
func = fdiv_op;
if (func != -1) {
mips32_insn.fp0_format.opcode = cop1_op;
mips32_insn.fp0_format.fmt =
sdps_format[insn.mm_fp0_format.fmt];
mips32_insn.fp0_format.ft =
insn.mm_fp0_format.ft;
mips32_insn.fp0_format.fs =
insn.mm_fp0_format.fs;
mips32_insn.fp0_format.fd =
insn.mm_fp0_format.fd;
mips32_insn.fp0_format.func = func;
} else
return SIGILL;
break;
case mm_32f_70_op:
func = -1; /* Invalid */
if (insn.mm_fp0_format.op == mm_fmovn_op)
func = fmovn_op;
else if (insn.mm_fp0_format.op == mm_fmovz_op)
func = fmovz_op;
if (func != -1) {
mips32_insn.fp0_format.opcode = cop1_op;
mips32_insn.fp0_format.fmt =
sdps_format[insn.mm_fp0_format.fmt];
mips32_insn.fp0_format.ft =
insn.mm_fp0_format.ft;
mips32_insn.fp0_format.fs =
insn.mm_fp0_format.fs;
mips32_insn.fp0_format.fd =
insn.mm_fp0_format.fd;
mips32_insn.fp0_format.func = func;
} else
return SIGILL;
break;
case mm_32f_73_op: /* POOL32FXF */
switch (insn.mm_fp1_format.op) {
case mm_movf0_op:
case mm_movf1_op:
case mm_movt0_op:
case mm_movt1_op:
if ((insn.mm_fp1_format.op & 0x7f) ==
mm_movf0_op)
op = 0;
else
op = 1;
mips32_insn.r_format.opcode = spec_op;
mips32_insn.r_format.rs = insn.mm_fp4_format.fs;
mips32_insn.r_format.rt =
(insn.mm_fp4_format.cc << 2) + op;
mips32_insn.r_format.rd = insn.mm_fp4_format.rt;
mips32_insn.r_format.re = 0;
mips32_insn.r_format.func = movc_op;
break;
case mm_fcvtd0_op:
case mm_fcvtd1_op:
case mm_fcvts0_op:
case mm_fcvts1_op:
if ((insn.mm_fp1_format.op & 0x7f) ==
mm_fcvtd0_op) {
func = fcvtd_op;
fmt = swl_format[insn.mm_fp3_format.fmt];
} else {
func = fcvts_op;
fmt = dwl_format[insn.mm_fp3_format.fmt];
}
mips32_insn.fp0_format.opcode = cop1_op;
mips32_insn.fp0_format.fmt = fmt;
mips32_insn.fp0_format.ft = 0;
mips32_insn.fp0_format.fs =
insn.mm_fp3_format.fs;
mips32_insn.fp0_format.fd =
insn.mm_fp3_format.rt;
mips32_insn.fp0_format.func = func;
break;
case mm_fmov0_op:
case mm_fmov1_op:
case mm_fabs0_op:
case mm_fabs1_op:
case mm_fneg0_op:
case mm_fneg1_op:
if ((insn.mm_fp1_format.op & 0x7f) ==
mm_fmov0_op)
func = fmov_op;
else if ((insn.mm_fp1_format.op & 0x7f) ==
mm_fabs0_op)
func = fabs_op;
else
func = fneg_op;
mips32_insn.fp0_format.opcode = cop1_op;
mips32_insn.fp0_format.fmt =
sdps_format[insn.mm_fp3_format.fmt];
mips32_insn.fp0_format.ft = 0;
mips32_insn.fp0_format.fs =
insn.mm_fp3_format.fs;
mips32_insn.fp0_format.fd =
insn.mm_fp3_format.rt;
mips32_insn.fp0_format.func = func;
break;
case mm_ffloorl_op:
case mm_ffloorw_op:
case mm_fceill_op:
case mm_fceilw_op:
case mm_ftruncl_op:
case mm_ftruncw_op:
case mm_froundl_op:
case mm_froundw_op:
case mm_fcvtl_op:
case mm_fcvtw_op:
if (insn.mm_fp1_format.op == mm_ffloorl_op)
func = ffloorl_op;
else if (insn.mm_fp1_format.op == mm_ffloorw_op)
func = ffloor_op;
else if (insn.mm_fp1_format.op == mm_fceill_op)
func = fceill_op;
else if (insn.mm_fp1_format.op == mm_fceilw_op)
func = fceil_op;
else if (insn.mm_fp1_format.op == mm_ftruncl_op)
func = ftruncl_op;
else if (insn.mm_fp1_format.op == mm_ftruncw_op)
func = ftrunc_op;
else if (insn.mm_fp1_format.op == mm_froundl_op)
func = froundl_op;
else if (insn.mm_fp1_format.op == mm_froundw_op)
func = fround_op;
else if (insn.mm_fp1_format.op == mm_fcvtl_op)
func = fcvtl_op;
else
func = fcvtw_op;
mips32_insn.fp0_format.opcode = cop1_op;
mips32_insn.fp0_format.fmt =
sd_format[insn.mm_fp1_format.fmt];
mips32_insn.fp0_format.ft = 0;
mips32_insn.fp0_format.fs =
insn.mm_fp1_format.fs;
mips32_insn.fp0_format.fd =
insn.mm_fp1_format.rt;
mips32_insn.fp0_format.func = func;
break;
case mm_frsqrt_op:
case mm_fsqrt_op:
case mm_frecip_op:
if (insn.mm_fp1_format.op == mm_frsqrt_op)
func = frsqrt_op;
else if (insn.mm_fp1_format.op == mm_fsqrt_op)
func = fsqrt_op;
else
func = frecip_op;
mips32_insn.fp0_format.opcode = cop1_op;
mips32_insn.fp0_format.fmt =
sdps_format[insn.mm_fp1_format.fmt];
mips32_insn.fp0_format.ft = 0;
mips32_insn.fp0_format.fs =
insn.mm_fp1_format.fs;
mips32_insn.fp0_format.fd =
insn.mm_fp1_format.rt;
mips32_insn.fp0_format.func = func;
break;
case mm_mfc1_op:
case mm_mtc1_op:
case mm_cfc1_op:
case mm_ctc1_op:
if (insn.mm_fp1_format.op == mm_mfc1_op)
op = mfc_op;
else if (insn.mm_fp1_format.op == mm_mtc1_op)
op = mtc_op;
else if (insn.mm_fp1_format.op == mm_cfc1_op)
op = cfc_op;
else
op = ctc_op;
mips32_insn.fp1_format.opcode = cop1_op;
mips32_insn.fp1_format.op = op;
mips32_insn.fp1_format.rt =
insn.mm_fp1_format.rt;
mips32_insn.fp1_format.fs =
insn.mm_fp1_format.fs;
mips32_insn.fp1_format.fd = 0;
mips32_insn.fp1_format.func = 0;
break;
default:
return SIGILL;
break;
}
break;
case mm_32f_74_op: /* c.cond.fmt */
mips32_insn.fp0_format.opcode = cop1_op;
mips32_insn.fp0_format.fmt =
sdps_format[insn.mm_fp4_format.fmt];
mips32_insn.fp0_format.ft = insn.mm_fp4_format.rt;
mips32_insn.fp0_format.fs = insn.mm_fp4_format.fs;
mips32_insn.fp0_format.fd = insn.mm_fp4_format.cc << 2;
mips32_insn.fp0_format.func =
insn.mm_fp4_format.cond | MM_MIPS32_COND_FC;
break;
default:
return SIGILL;
break;
}
break;
default:
return SIGILL;
break;
}
*insn_ptr = mips32_insn;
return 0;
}
int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
unsigned long *contpc)
{
union mips_instruction insn = (union mips_instruction)dec_insn.insn;
int bc_false = 0;
unsigned int fcr31;
unsigned int bit;
switch (insn.mm_i_format.opcode) {
case mm_pool32a_op:
if ((insn.mm_i_format.simmediate & MM_POOL32A_MINOR_MASK) ==
mm_pool32axf_op) {
switch (insn.mm_i_format.simmediate >>
MM_POOL32A_MINOR_SHIFT) {
case mm_jalr_op:
case mm_jalrhb_op:
case mm_jalrs_op:
case mm_jalrshb_op:
if (insn.mm_i_format.rt != 0) /* Not mm_jr */
regs->regs[insn.mm_i_format.rt] =
regs->cp0_epc +
dec_insn.pc_inc +
dec_insn.next_pc_inc;
*contpc = regs->regs[insn.mm_i_format.rs];
return 1;
break;
}
}
break;
case mm_pool32i_op:
switch (insn.mm_i_format.rt) {
case mm_bltzals_op:
case mm_bltzal_op:
regs->regs[31] = regs->cp0_epc +
dec_insn.pc_inc +
dec_insn.next_pc_inc;
/* Fall through */
case mm_bltz_op:
if ((long)regs->regs[insn.mm_i_format.rs] < 0)
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
(insn.mm_i_format.simmediate << 1);
else
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1;
break;
case mm_bgezals_op:
case mm_bgezal_op:
regs->regs[31] = regs->cp0_epc +
dec_insn.pc_inc +
dec_insn.next_pc_inc;
/* Fall through */
case mm_bgez_op:
if ((long)regs->regs[insn.mm_i_format.rs] >= 0)
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
(insn.mm_i_format.simmediate << 1);
else
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1;
break;
case mm_blez_op:
if ((long)regs->regs[insn.mm_i_format.rs] <= 0)
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
(insn.mm_i_format.simmediate << 1);
else
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1;
break;
case mm_bgtz_op:
if ((long)regs->regs[insn.mm_i_format.rs] <= 0)
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
(insn.mm_i_format.simmediate << 1);
else
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1;
break;
case mm_bc2f_op:
case mm_bc1f_op:
bc_false = 1;
/* Fall through */
case mm_bc2t_op:
case mm_bc1t_op:
preempt_disable();
if (is_fpu_owner())
asm volatile("cfc1\t%0,$31" : "=r" (fcr31));
else
fcr31 = current->thread.fpu.fcr31;
preempt_enable();
if (bc_false)
fcr31 = ~fcr31;
bit = (insn.mm_i_format.rs >> 2);
bit += (bit != 0);
bit += 23;
if (fcr31 & (1 << bit))
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
(insn.mm_i_format.simmediate << 1);
else
*contpc = regs->cp0_epc +
dec_insn.pc_inc + dec_insn.next_pc_inc;
return 1;
break;
}
break;
case mm_pool16c_op:
switch (insn.mm_i_format.rt) {
case mm_jalr16_op:
case mm_jalrs16_op:
regs->regs[31] = regs->cp0_epc +
dec_insn.pc_inc + dec_insn.next_pc_inc;
/* Fall through */
case mm_jr16_op:
*contpc = regs->regs[insn.mm_i_format.rs];
return 1;
break;
}
break;
case mm_beqz16_op:
if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] == 0)
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
(insn.mm_b1_format.simmediate << 1);
else
*contpc = regs->cp0_epc +
dec_insn.pc_inc + dec_insn.next_pc_inc;
return 1;
break;
case mm_bnez16_op:
if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] != 0)
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
(insn.mm_b1_format.simmediate << 1);
else
*contpc = regs->cp0_epc +
dec_insn.pc_inc + dec_insn.next_pc_inc;
return 1;
break;
case mm_b16_op:
*contpc = regs->cp0_epc + dec_insn.pc_inc +
(insn.mm_b0_format.simmediate << 1);
return 1;
break;
case mm_beq32_op:
if (regs->regs[insn.mm_i_format.rs] ==
regs->regs[insn.mm_i_format.rt])
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
(insn.mm_i_format.simmediate << 1);
else
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1;
break;
case mm_bne32_op:
if (regs->regs[insn.mm_i_format.rs] !=
regs->regs[insn.mm_i_format.rt])
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
(insn.mm_i_format.simmediate << 1);
else
*contpc = regs->cp0_epc +
dec_insn.pc_inc + dec_insn.next_pc_inc;
return 1;
break;
case mm_jalx32_op:
regs->regs[31] = regs->cp0_epc +
dec_insn.pc_inc + dec_insn.next_pc_inc;
*contpc = regs->cp0_epc + dec_insn.pc_inc;
*contpc >>= 28;
*contpc <<= 28;
*contpc |= (insn.j_format.target << 2);
return 1;
break;
case mm_jals32_op:
case mm_jal32_op:
regs->regs[31] = regs->cp0_epc +
dec_insn.pc_inc + dec_insn.next_pc_inc;
/* Fall through */
case mm_j32_op:
*contpc = regs->cp0_epc + dec_insn.pc_inc;
*contpc >>= 27;
*contpc <<= 27;
*contpc |= (insn.j_format.target << 1);
set_isa16_mode(*contpc);
return 1;
break;
}
return 0;
}
/* /*
* Redundant with logic already in kernel/branch.c, * Redundant with logic already in kernel/branch.c,
...@@ -117,53 +673,177 @@ static const unsigned int fpucondbit[8] = { ...@@ -117,53 +673,177 @@ static const unsigned int fpucondbit[8] = {
* a single subroutine should be used across both * a single subroutine should be used across both
* modules. * modules.
*/ */
static int isBranchInstr(mips_instruction * i) static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
unsigned long *contpc)
{ {
switch (MIPSInst_OPCODE(*i)) { union mips_instruction insn = (union mips_instruction)dec_insn.insn;
unsigned int fcr31;
unsigned int bit = 0;
switch (insn.i_format.opcode) {
case spec_op: case spec_op:
switch (MIPSInst_FUNC(*i)) { switch (insn.r_format.func) {
case jalr_op: case jalr_op:
regs->regs[insn.r_format.rd] =
regs->cp0_epc + dec_insn.pc_inc +
dec_insn.next_pc_inc;
/* Fall through */
case jr_op: case jr_op:
*contpc = regs->regs[insn.r_format.rs];
return 1; return 1;
break;
} }
break; break;
case bcond_op: case bcond_op:
switch (MIPSInst_RT(*i)) { switch (insn.i_format.rt) {
case bltzal_op:
case bltzall_op:
regs->regs[31] = regs->cp0_epc +
dec_insn.pc_inc +
dec_insn.next_pc_inc;
/* Fall through */
case bltz_op: case bltz_op:
case bgez_op:
case bltzl_op: case bltzl_op:
case bgezl_op: if ((long)regs->regs[insn.i_format.rs] < 0)
case bltzal_op: *contpc = regs->cp0_epc +
dec_insn.pc_inc +
(insn.i_format.simmediate << 2);
else
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1;
break;
case bgezal_op: case bgezal_op:
case bltzall_op:
case bgezall_op: case bgezall_op:
regs->regs[31] = regs->cp0_epc +
dec_insn.pc_inc +
dec_insn.next_pc_inc;
/* Fall through */
case bgez_op:
case bgezl_op:
if ((long)regs->regs[insn.i_format.rs] >= 0)
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
(insn.i_format.simmediate << 2);
else
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1; return 1;
break;
} }
break; break;
case j_op:
case jal_op:
case jalx_op: case jalx_op:
set_isa16_mode(bit);
case jal_op:
regs->regs[31] = regs->cp0_epc +
dec_insn.pc_inc +
dec_insn.next_pc_inc;
/* Fall through */
case j_op:
*contpc = regs->cp0_epc + dec_insn.pc_inc;
*contpc >>= 28;
*contpc <<= 28;
*contpc |= (insn.j_format.target << 2);
/* Set microMIPS mode bit: XOR for jalx. */
*contpc ^= bit;
return 1;
break;
case beq_op: case beq_op:
case bne_op:
case blez_op:
case bgtz_op:
case beql_op: case beql_op:
if (regs->regs[insn.i_format.rs] ==
regs->regs[insn.i_format.rt])
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
(insn.i_format.simmediate << 2);
else
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1;
break;
case bne_op:
case bnel_op: case bnel_op:
if (regs->regs[insn.i_format.rs] !=
regs->regs[insn.i_format.rt])
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
(insn.i_format.simmediate << 2);
else
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1;
break;
case blez_op:
case blezl_op: case blezl_op:
if ((long)regs->regs[insn.i_format.rs] <= 0)
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
(insn.i_format.simmediate << 2);
else
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1;
break;
case bgtz_op:
case bgtzl_op: case bgtzl_op:
if ((long)regs->regs[insn.i_format.rs] > 0)
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
(insn.i_format.simmediate << 2);
else
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1; return 1;
break;
case cop0_op: case cop0_op:
case cop1_op: case cop1_op:
case cop2_op: case cop2_op:
case cop1x_op: case cop1x_op:
if (MIPSInst_RS(*i) == bc_op) if (insn.i_format.rs == bc_op) {
return 1; preempt_disable();
if (is_fpu_owner())
asm volatile("cfc1\t%0,$31" : "=r" (fcr31));
else
fcr31 = current->thread.fpu.fcr31;
preempt_enable();
bit = (insn.i_format.rt >> 2);
bit += (bit != 0);
bit += 23;
switch (insn.i_format.rt & 3) {
case 0: /* bc1f */
case 2: /* bc1fl */
if (~fcr31 & (1 << bit))
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
(insn.i_format.simmediate << 2);
else
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1;
break;
case 1: /* bc1t */
case 3: /* bc1tl */
if (fcr31 & (1 << bit))
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
(insn.i_format.simmediate << 2);
else
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1;
break;
}
}
break; break;
} }
return 0; return 0;
} }
...@@ -210,26 +890,23 @@ static inline int cop1_64bit(struct pt_regs *xcp) ...@@ -210,26 +890,23 @@ static inline int cop1_64bit(struct pt_regs *xcp)
*/ */
static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
void *__user *fault_addr) struct mm_decoded_insn dec_insn, void *__user *fault_addr)
{ {
mips_instruction ir; mips_instruction ir;
unsigned long emulpc, contpc; unsigned long contpc = xcp->cp0_epc + dec_insn.pc_inc;
unsigned int cond; unsigned int cond;
int pc_inc;
if (!access_ok(VERIFY_READ, xcp->cp0_epc, sizeof(mips_instruction))) {
MIPS_FPU_EMU_INC_STATS(errors);
*fault_addr = (mips_instruction __user *)xcp->cp0_epc;
return SIGBUS;
}
if (__get_user(ir, (mips_instruction __user *) xcp->cp0_epc)) {
MIPS_FPU_EMU_INC_STATS(errors);
*fault_addr = (mips_instruction __user *)xcp->cp0_epc;
return SIGSEGV;
}
/* XXX NEC Vr54xx bug workaround */ /* XXX NEC Vr54xx bug workaround */
if ((xcp->cp0_cause & CAUSEF_BD) && !isBranchInstr(&ir)) if (xcp->cp0_cause & CAUSEF_BD) {
xcp->cp0_cause &= ~CAUSEF_BD; if (dec_insn.micro_mips_mode) {
if (!mm_isBranchInstr(xcp, dec_insn, &contpc))
xcp->cp0_cause &= ~CAUSEF_BD;
} else {
if (!isBranchInstr(xcp, dec_insn, &contpc))
xcp->cp0_cause &= ~CAUSEF_BD;
}
}
if (xcp->cp0_cause & CAUSEF_BD) { if (xcp->cp0_cause & CAUSEF_BD) {
/* /*
...@@ -244,32 +921,33 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, ...@@ -244,32 +921,33 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
* Linux MIPS branch emulator operates on context, updating the * Linux MIPS branch emulator operates on context, updating the
* cp0_epc. * cp0_epc.
*/ */
emulpc = xcp->cp0_epc + 4; /* Snapshot emulation target */ ir = dec_insn.next_insn; /* process delay slot instr */
pc_inc = dec_insn.next_pc_inc;
} else {
ir = dec_insn.insn; /* process current instr */
pc_inc = dec_insn.pc_inc;
}
if (__compute_return_epc(xcp) < 0) { /*
#ifdef CP1DBG * Since microMIPS FPU instructios are a subset of MIPS32 FPU
printk("failed to emulate branch at %p\n", * instructions, we want to convert microMIPS FPU instructions
(void *) (xcp->cp0_epc)); * into MIPS32 instructions so that we could reuse all of the
#endif * FPU emulation code.
*
* NOTE: We cannot do this for branch instructions since they
* are not a subset. Example: Cannot emulate a 16-bit
* aligned target address with a MIPS32 instruction.
*/
if (dec_insn.micro_mips_mode) {
/*
* If next instruction is a 16-bit instruction, then it
* it cannot be a FPU instruction. This could happen
* since we can be called for non-FPU instructions.
*/
if ((pc_inc == 2) ||
(microMIPS32_to_MIPS32((union mips_instruction *)&ir)
== SIGILL))
return SIGILL; return SIGILL;
}
if (!access_ok(VERIFY_READ, emulpc, sizeof(mips_instruction))) {
MIPS_FPU_EMU_INC_STATS(errors);
*fault_addr = (mips_instruction __user *)emulpc;
return SIGBUS;
}
if (__get_user(ir, (mips_instruction __user *) emulpc)) {
MIPS_FPU_EMU_INC_STATS(errors);
*fault_addr = (mips_instruction __user *)emulpc;
return SIGSEGV;
}
/* __compute_return_epc() will have updated cp0_epc */
contpc = xcp->cp0_epc;
/* In order not to confuse ptrace() et al, tweak context */
xcp->cp0_epc = emulpc - 4;
} else {
emulpc = xcp->cp0_epc;
contpc = xcp->cp0_epc + 4;
} }
emul: emul:
...@@ -474,22 +1152,35 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, ...@@ -474,22 +1152,35 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
/* branch taken: emulate dslot /* branch taken: emulate dslot
* instruction * instruction
*/ */
xcp->cp0_epc += 4; xcp->cp0_epc += dec_insn.pc_inc;
contpc = (xcp->cp0_epc +
(MIPSInst_SIMM(ir) << 2)); contpc = MIPSInst_SIMM(ir);
ir = dec_insn.next_insn;
if (!access_ok(VERIFY_READ, xcp->cp0_epc, if (dec_insn.micro_mips_mode) {
sizeof(mips_instruction))) { contpc = (xcp->cp0_epc + (contpc << 1));
MIPS_FPU_EMU_INC_STATS(errors);
*fault_addr = (mips_instruction __user *)xcp->cp0_epc; /* If 16-bit instruction, not FPU. */
return SIGBUS; if ((dec_insn.next_pc_inc == 2) ||
} (microMIPS32_to_MIPS32((union mips_instruction *)&ir) == SIGILL)) {
if (__get_user(ir,
(mips_instruction __user *) xcp->cp0_epc)) { /*
MIPS_FPU_EMU_INC_STATS(errors); * Since this instruction will
*fault_addr = (mips_instruction __user *)xcp->cp0_epc; * be put on the stack with
return SIGSEGV; * 32-bit words, get around
} * this problem by putting a
* NOP16 as the second one.
*/
if (dec_insn.next_pc_inc == 2)
ir = (ir & (~0xffff)) | MM_NOP16;
/*
* Single step the non-CP1
* instruction in the dslot.
*/
return mips_dsemul(xcp, ir, contpc);
}
} else
contpc = (xcp->cp0_epc + (contpc << 2));
switch (MIPSInst_OPCODE(ir)) { switch (MIPSInst_OPCODE(ir)) {
case lwc1_op: case lwc1_op:
...@@ -525,8 +1216,8 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, ...@@ -525,8 +1216,8 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
* branch likely nullifies * branch likely nullifies
* dslot if not taken * dslot if not taken
*/ */
xcp->cp0_epc += 4; xcp->cp0_epc += dec_insn.pc_inc;
contpc += 4; contpc += dec_insn.pc_inc;
/* /*
* else continue & execute * else continue & execute
* dslot as normal insn * dslot as normal insn
...@@ -1313,25 +2004,75 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, ...@@ -1313,25 +2004,75 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
int has_fpu, void *__user *fault_addr) int has_fpu, void *__user *fault_addr)
{ {
unsigned long oldepc, prevepc; unsigned long oldepc, prevepc;
mips_instruction insn; struct mm_decoded_insn dec_insn;
u16 instr[4];
u16 *instr_ptr;
int sig = 0; int sig = 0;
oldepc = xcp->cp0_epc; oldepc = xcp->cp0_epc;
do { do {
prevepc = xcp->cp0_epc; prevepc = xcp->cp0_epc;
if (!access_ok(VERIFY_READ, xcp->cp0_epc, sizeof(mips_instruction))) { if (get_isa16_mode(prevepc) && cpu_has_mmips) {
MIPS_FPU_EMU_INC_STATS(errors); /*
*fault_addr = (mips_instruction __user *)xcp->cp0_epc; * Get next 2 microMIPS instructions and convert them
return SIGBUS; * into 32-bit instructions.
} */
if (__get_user(insn, (mips_instruction __user *) xcp->cp0_epc)) { if ((get_user(instr[0], (u16 __user *)msk_isa16_mode(xcp->cp0_epc))) ||
MIPS_FPU_EMU_INC_STATS(errors); (get_user(instr[1], (u16 __user *)msk_isa16_mode(xcp->cp0_epc + 2))) ||
*fault_addr = (mips_instruction __user *)xcp->cp0_epc; (get_user(instr[2], (u16 __user *)msk_isa16_mode(xcp->cp0_epc + 4))) ||
return SIGSEGV; (get_user(instr[3], (u16 __user *)msk_isa16_mode(xcp->cp0_epc + 6)))) {
MIPS_FPU_EMU_INC_STATS(errors);
return SIGBUS;
}
instr_ptr = instr;
/* Get first instruction. */
if (mm_insn_16bit(*instr_ptr)) {
/* Duplicate the half-word. */
dec_insn.insn = (*instr_ptr << 16) |
(*instr_ptr);
/* 16-bit instruction. */
dec_insn.pc_inc = 2;
instr_ptr += 1;
} else {
dec_insn.insn = (*instr_ptr << 16) |
*(instr_ptr+1);
/* 32-bit instruction. */
dec_insn.pc_inc = 4;
instr_ptr += 2;
}
/* Get second instruction. */
if (mm_insn_16bit(*instr_ptr)) {
/* Duplicate the half-word. */
dec_insn.next_insn = (*instr_ptr << 16) |
(*instr_ptr);
/* 16-bit instruction. */
dec_insn.next_pc_inc = 2;
} else {
dec_insn.next_insn = (*instr_ptr << 16) |
*(instr_ptr+1);
/* 32-bit instruction. */
dec_insn.next_pc_inc = 4;
}
dec_insn.micro_mips_mode = 1;
} else {
if ((get_user(dec_insn.insn,
(mips_instruction __user *) xcp->cp0_epc)) ||
(get_user(dec_insn.next_insn,
(mips_instruction __user *)(xcp->cp0_epc+4)))) {
MIPS_FPU_EMU_INC_STATS(errors);
return SIGBUS;
}
dec_insn.pc_inc = 4;
dec_insn.next_pc_inc = 4;
dec_insn.micro_mips_mode = 0;
} }
if (insn == 0)
xcp->cp0_epc += 4; /* skip nops */ if ((dec_insn.insn == 0) ||
((dec_insn.pc_inc == 2) &&
((dec_insn.insn & 0xffff) == MM_NOP16)))
xcp->cp0_epc += dec_insn.pc_inc; /* Skip NOPs */
else { else {
/* /*
* The 'ieee754_csr' is an alias of * The 'ieee754_csr' is an alias of
...@@ -1341,7 +2082,7 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, ...@@ -1341,7 +2082,7 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
*/ */
/* convert to ieee library modes */ /* convert to ieee library modes */
ieee754_csr.rm = ieee_rm[ieee754_csr.rm]; ieee754_csr.rm = ieee_rm[ieee754_csr.rm];
sig = cop1Emulate(xcp, ctx, fault_addr); sig = cop1Emulate(xcp, ctx, dec_insn, fault_addr);
/* revert to mips rounding mode */ /* revert to mips rounding mode */
ieee754_csr.rm = mips_rm[ieee754_csr.rm]; ieee754_csr.rm = mips_rm[ieee754_csr.rm];
} }
......
...@@ -55,7 +55,9 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) ...@@ -55,7 +55,9 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc)
struct emuframe __user *fr; struct emuframe __user *fr;
int err; int err;
if (ir == 0) { /* a nop is easy */ if ((get_isa16_mode(regs->cp0_epc) && ((ir >> 16) == MM_NOP16)) ||
(ir == 0)) {
/* NOP is easy */
regs->cp0_epc = cpc; regs->cp0_epc = cpc;
regs->cp0_cause &= ~CAUSEF_BD; regs->cp0_cause &= ~CAUSEF_BD;
return 0; return 0;
...@@ -91,8 +93,16 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) ...@@ -91,8 +93,16 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc)
if (unlikely(!access_ok(VERIFY_WRITE, fr, sizeof(struct emuframe)))) if (unlikely(!access_ok(VERIFY_WRITE, fr, sizeof(struct emuframe))))
return SIGBUS; return SIGBUS;
err = __put_user(ir, &fr->emul); if (get_isa16_mode(regs->cp0_epc)) {
err |= __put_user((mips_instruction)BREAK_MATH, &fr->badinst); err = __put_user(ir >> 16, (u16 __user *)(&fr->emul));
err |= __put_user(ir & 0xffff, (u16 __user *)((long)(&fr->emul) + 2));
err |= __put_user(BREAK_MATH >> 16, (u16 __user *)(&fr->badinst));
err |= __put_user(BREAK_MATH & 0xffff, (u16 __user *)((long)(&fr->badinst) + 2));
} else {
err = __put_user(ir, &fr->emul);
err |= __put_user((mips_instruction)BREAK_MATH, &fr->badinst);
}
err |= __put_user((mips_instruction)BD_COOKIE, &fr->cookie); err |= __put_user((mips_instruction)BD_COOKIE, &fr->cookie);
err |= __put_user(cpc, &fr->epc); err |= __put_user(cpc, &fr->epc);
...@@ -101,7 +111,8 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) ...@@ -101,7 +111,8 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc)
return SIGBUS; return SIGBUS;
} }
regs->cp0_epc = (unsigned long) &fr->emul; regs->cp0_epc = ((unsigned long) &fr->emul) |
get_isa16_mode(regs->cp0_epc);
flush_cache_sigtramp((unsigned long)&fr->badinst); flush_cache_sigtramp((unsigned long)&fr->badinst);
...@@ -114,9 +125,10 @@ int do_dsemulret(struct pt_regs *xcp) ...@@ -114,9 +125,10 @@ int do_dsemulret(struct pt_regs *xcp)
unsigned long epc; unsigned long epc;
u32 insn, cookie; u32 insn, cookie;
int err = 0; int err = 0;
u16 instr[2];
fr = (struct emuframe __user *) fr = (struct emuframe __user *)
(xcp->cp0_epc - sizeof(mips_instruction)); (msk_isa16_mode(xcp->cp0_epc) - sizeof(mips_instruction));
/* /*
* If we can't even access the area, something is very wrong, but we'll * If we can't even access the area, something is very wrong, but we'll
...@@ -131,7 +143,13 @@ int do_dsemulret(struct pt_regs *xcp) ...@@ -131,7 +143,13 @@ int do_dsemulret(struct pt_regs *xcp)
* - Is the instruction pointed to by the EPC an BREAK_MATH? * - Is the instruction pointed to by the EPC an BREAK_MATH?
* - Is the following memory word the BD_COOKIE? * - Is the following memory word the BD_COOKIE?
*/ */
err = __get_user(insn, &fr->badinst); if (get_isa16_mode(xcp->cp0_epc)) {
err = __get_user(instr[0], (u16 __user *)(&fr->badinst));
err |= __get_user(instr[1], (u16 __user *)((long)(&fr->badinst) + 2));
insn = (instr[0] << 16) | instr[1];
} else {
err = __get_user(insn, &fr->badinst);
}
err |= __get_user(cookie, &fr->cookie); err |= __get_user(cookie, &fr->cookie);
if (unlikely(err || (insn != BREAK_MATH) || (cookie != BD_COOKIE))) { if (unlikely(err || (insn != BREAK_MATH) || (cookie != BD_COOKIE))) {
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
obj-y += cache.o dma-default.o extable.o fault.o \ obj-y += cache.o dma-default.o extable.o fault.o \
gup.o init.o mmap.o page.o page-funcs.o \ gup.o init.o mmap.o page.o page-funcs.o \
tlbex.o tlbex-fault.o uasm.o tlbex.o tlbex-fault.o uasm-mips.o
obj-$(CONFIG_32BIT) += ioremap.o pgtable-32.o obj-$(CONFIG_32BIT) += ioremap.o pgtable-32.o
obj-$(CONFIG_64BIT) += pgtable-64.o obj-$(CONFIG_64BIT) += pgtable-64.o
...@@ -22,3 +22,5 @@ obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o ...@@ -22,3 +22,5 @@ obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o
obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o
obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o
obj-$(CONFIG_MIPS_CPU_SCACHE) += sc-mips.o obj-$(CONFIG_MIPS_CPU_SCACHE) += sc-mips.o
obj-$(CONFIG_SYS_SUPPORTS_MICROMIPS) += uasm-micromips.o
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <asm/war.h> #include <asm/war.h>
#include <asm/cacheflush.h> /* for run_uncached() */ #include <asm/cacheflush.h> /* for run_uncached() */
#include <asm/traps.h> #include <asm/traps.h>
#include <asm/dma-coherence.h>
/* /*
* Special Variant of smp_call_function for use by cache functions: * Special Variant of smp_call_function for use by cache functions:
...@@ -1379,20 +1380,6 @@ static void __cpuinit coherency_setup(void) ...@@ -1379,20 +1380,6 @@ static void __cpuinit coherency_setup(void)
} }
} }
#if defined(CONFIG_DMA_NONCOHERENT)
static int __cpuinitdata coherentio;
static int __init setcoherentio(char *str)
{
coherentio = 1;
return 0;
}
early_param("coherentio", setcoherentio);
#endif
static void __cpuinit r4k_cache_error_setup(void) static void __cpuinit r4k_cache_error_setup(void)
{ {
extern char __weak except_vec2_generic; extern char __weak except_vec2_generic;
...@@ -1474,9 +1461,14 @@ void __cpuinit r4k_cache_init(void) ...@@ -1474,9 +1461,14 @@ void __cpuinit r4k_cache_init(void)
build_clear_page(); build_clear_page();
build_copy_page(); build_copy_page();
#if !defined(CONFIG_MIPS_CMP)
/*
* We want to run CMP kernels on core with and without coherent
* caches. Therefore, do not use CONFIG_MIPS_CMP to decide whether
* or not to flush caches.
*/
local_r4k___flush_cache_all(NULL); local_r4k___flush_cache_all(NULL);
#endif
coherency_setup(); coherency_setup();
board_cache_error_setup = r4k_cache_error_setup; board_cache_error_setup = r4k_cache_error_setup;
} }
...@@ -22,6 +22,26 @@ ...@@ -22,6 +22,26 @@
#include <dma-coherence.h> #include <dma-coherence.h>
int coherentio = 0; /* User defined DMA coherency from command line. */
EXPORT_SYMBOL_GPL(coherentio);
int hw_coherentio = 0; /* Actual hardware supported DMA coherency setting. */
static int __init setcoherentio(char *str)
{
coherentio = 1;
pr_info("Hardware DMA cache coherency (command line)\n");
return 0;
}
early_param("coherentio", setcoherentio);
static int __init setnocoherentio(char *str)
{
coherentio = 0;
pr_info("Software DMA cache coherency (command line)\n");
return 0;
}
early_param("nocoherentio", setnocoherentio);
static inline struct page *dma_addr_to_page(struct device *dev, static inline struct page *dma_addr_to_page(struct device *dev,
dma_addr_t dma_addr) dma_addr_t dma_addr)
{ {
...@@ -115,7 +135,8 @@ static void *mips_dma_alloc_coherent(struct device *dev, size_t size, ...@@ -115,7 +135,8 @@ static void *mips_dma_alloc_coherent(struct device *dev, size_t size,
if (!plat_device_is_coherent(dev)) { if (!plat_device_is_coherent(dev)) {
dma_cache_wback_inv((unsigned long) ret, size); dma_cache_wback_inv((unsigned long) ret, size);
ret = UNCAC_ADDR(ret); if (!hw_coherentio)
ret = UNCAC_ADDR(ret);
} }
} }
...@@ -142,7 +163,7 @@ static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr, ...@@ -142,7 +163,7 @@ static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
plat_unmap_dma_mem(dev, dma_handle, size, DMA_BIDIRECTIONAL); plat_unmap_dma_mem(dev, dma_handle, size, DMA_BIDIRECTIONAL);
if (!plat_device_is_coherent(dev)) if (!plat_device_is_coherent(dev) && !hw_coherentio)
addr = CAC_ADDR(addr); addr = CAC_ADDR(addr);
free_pages(addr, get_order(size)); free_pages(addr, get_order(size));
......
...@@ -51,7 +51,7 @@ void local_flush_tlb_all(void) ...@@ -51,7 +51,7 @@ void local_flush_tlb_all(void)
#endif #endif
local_irq_save(flags); local_irq_save(flags);
old_ctx = read_c0_entryhi() & ASID_MASK; old_ctx = ASID_MASK(read_c0_entryhi());
write_c0_entrylo0(0); write_c0_entrylo0(0);
entry = r3k_have_wired_reg ? read_c0_wired() : 8; entry = r3k_have_wired_reg ? read_c0_wired() : 8;
for (; entry < current_cpu_data.tlbsize; entry++) { for (; entry < current_cpu_data.tlbsize; entry++) {
...@@ -87,13 +87,13 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, ...@@ -87,13 +87,13 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
#ifdef DEBUG_TLB #ifdef DEBUG_TLB
printk("[tlbrange<%lu,0x%08lx,0x%08lx>]", printk("[tlbrange<%lu,0x%08lx,0x%08lx>]",
cpu_context(cpu, mm) & ASID_MASK, start, end); ASID_MASK(cpu_context(cpu, mm)), start, end);
#endif #endif
local_irq_save(flags); local_irq_save(flags);
size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
if (size <= current_cpu_data.tlbsize) { if (size <= current_cpu_data.tlbsize) {
int oldpid = read_c0_entryhi() & ASID_MASK; int oldpid = ASID_MASK(read_c0_entryhi());
int newpid = cpu_context(cpu, mm) & ASID_MASK; int newpid = ASID_MASK(cpu_context(cpu, mm));
start &= PAGE_MASK; start &= PAGE_MASK;
end += PAGE_SIZE - 1; end += PAGE_SIZE - 1;
...@@ -166,10 +166,10 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) ...@@ -166,10 +166,10 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
#ifdef DEBUG_TLB #ifdef DEBUG_TLB
printk("[tlbpage<%lu,0x%08lx>]", cpu_context(cpu, vma->vm_mm), page); printk("[tlbpage<%lu,0x%08lx>]", cpu_context(cpu, vma->vm_mm), page);
#endif #endif
newpid = cpu_context(cpu, vma->vm_mm) & ASID_MASK; newpid = ASID_MASK(cpu_context(cpu, vma->vm_mm));
page &= PAGE_MASK; page &= PAGE_MASK;
local_irq_save(flags); local_irq_save(flags);
oldpid = read_c0_entryhi() & ASID_MASK; oldpid = ASID_MASK(read_c0_entryhi());
write_c0_entryhi(page | newpid); write_c0_entryhi(page | newpid);
BARRIER; BARRIER;
tlb_probe(); tlb_probe();
...@@ -197,10 +197,10 @@ void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) ...@@ -197,10 +197,10 @@ void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte)
if (current->active_mm != vma->vm_mm) if (current->active_mm != vma->vm_mm)
return; return;
pid = read_c0_entryhi() & ASID_MASK; pid = ASID_MASK(read_c0_entryhi());
#ifdef DEBUG_TLB #ifdef DEBUG_TLB
if ((pid != (cpu_context(cpu, vma->vm_mm) & ASID_MASK)) || (cpu_context(cpu, vma->vm_mm) == 0)) { if ((pid != ASID_MASK(cpu_context(cpu, vma->vm_mm))) || (cpu_context(cpu, vma->vm_mm) == 0)) {
printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%lu tlbpid=%d\n", printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%lu tlbpid=%d\n",
(cpu_context(cpu, vma->vm_mm)), pid); (cpu_context(cpu, vma->vm_mm)), pid);
} }
...@@ -241,7 +241,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, ...@@ -241,7 +241,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
local_irq_save(flags); local_irq_save(flags);
/* Save old context and create impossible VPN2 value */ /* Save old context and create impossible VPN2 value */
old_ctx = read_c0_entryhi() & ASID_MASK; old_ctx = ASID_MASK(read_c0_entryhi());
old_pagemask = read_c0_pagemask(); old_pagemask = read_c0_pagemask();
w = read_c0_wired(); w = read_c0_wired();
write_c0_wired(w + 1); write_c0_wired(w + 1);
...@@ -264,7 +264,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, ...@@ -264,7 +264,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
#endif #endif
local_irq_save(flags); local_irq_save(flags);
old_ctx = read_c0_entryhi() & ASID_MASK; old_ctx = ASID_MASK(read_c0_entryhi());
write_c0_entrylo0(entrylo0); write_c0_entrylo0(entrylo0);
write_c0_entryhi(entryhi); write_c0_entryhi(entryhi);
write_c0_index(wired); write_c0_index(wired);
......
...@@ -287,7 +287,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) ...@@ -287,7 +287,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
ENTER_CRITICAL(flags); ENTER_CRITICAL(flags);
pid = read_c0_entryhi() & ASID_MASK; pid = ASID_MASK(read_c0_entryhi());
address &= (PAGE_MASK << 1); address &= (PAGE_MASK << 1);
write_c0_entryhi(address | pid); write_c0_entryhi(address | pid);
pgdp = pgd_offset(vma->vm_mm, address); pgdp = pgd_offset(vma->vm_mm, address);
......
...@@ -195,7 +195,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) ...@@ -195,7 +195,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
if (current->active_mm != vma->vm_mm) if (current->active_mm != vma->vm_mm)
return; return;
pid = read_c0_entryhi() & ASID_MASK; pid = ASID_MASK(read_c0_entryhi());
local_irq_save(flags); local_irq_save(flags);
address &= PAGE_MASK; address &= PAGE_MASK;
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/cache.h> #include <linux/cache.h>
#include <asm/mmu_context.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/war.h> #include <asm/war.h>
...@@ -305,6 +306,78 @@ static struct uasm_reloc relocs[128] __cpuinitdata; ...@@ -305,6 +306,78 @@ static struct uasm_reloc relocs[128] __cpuinitdata;
static int check_for_high_segbits __cpuinitdata; static int check_for_high_segbits __cpuinitdata;
#endif #endif
static void __cpuinit insn_fixup(unsigned int **start, unsigned int **stop,
unsigned int i_const)
{
unsigned int **p;
for (p = start; p < stop; p++) {
#ifndef CONFIG_CPU_MICROMIPS
unsigned int *ip;
ip = *p;
*ip = (*ip & 0xffff0000) | i_const;
#else
unsigned short *ip;
ip = ((unsigned short *)((unsigned int)*p - 1));
if ((*ip & 0xf000) == 0x4000) {
*ip &= 0xfff1;
*ip |= (i_const << 1);
} else if ((*ip & 0xf000) == 0x6000) {
*ip &= 0xfff1;
*ip |= ((i_const >> 2) << 1);
} else {
ip++;
*ip = i_const;
}
#endif
local_flush_icache_range((unsigned long)ip,
(unsigned long)ip + sizeof(*ip));
}
}
#define asid_insn_fixup(section, const) \
do { \
extern unsigned int *__start_ ## section; \
extern unsigned int *__stop_ ## section; \
insn_fixup(&__start_ ## section, &__stop_ ## section, const); \
} while(0)
/*
* Caller is assumed to flush the caches before the first context switch.
*/
static void __cpuinit setup_asid(unsigned int inc, unsigned int mask,
unsigned int version_mask,
unsigned int first_version)
{
extern asmlinkage void handle_ri_rdhwr_vivt(void);
unsigned long *vivt_exc;
#ifdef CONFIG_CPU_MICROMIPS
/*
* Worst case optimised microMIPS addiu instructions support
* only a 3-bit immediate value.
*/
if(inc > 7)
panic("Invalid ASID increment value!");
#endif
asid_insn_fixup(__asid_inc, inc);
asid_insn_fixup(__asid_mask, mask);
asid_insn_fixup(__asid_version_mask, version_mask);
asid_insn_fixup(__asid_first_version, first_version);
/* Patch up the 'handle_ri_rdhwr_vivt' handler. */
vivt_exc = (unsigned long *) &handle_ri_rdhwr_vivt;
#ifdef CONFIG_CPU_MICROMIPS
vivt_exc = (unsigned long *)((unsigned long) vivt_exc - 1);
#endif
vivt_exc++;
*vivt_exc = (*vivt_exc & ~mask) | mask;
current_cpu_data.asid_cache = first_version;
}
static int check_for_high_segbits __cpuinitdata; static int check_for_high_segbits __cpuinitdata;
static unsigned int kscratch_used_mask __cpuinitdata; static unsigned int kscratch_used_mask __cpuinitdata;
...@@ -2030,6 +2103,13 @@ static void __cpuinit build_r4000_tlb_load_handler(void) ...@@ -2030,6 +2103,13 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
uasm_l_nopage_tlbl(&l, p); uasm_l_nopage_tlbl(&l, p);
build_restore_work_registers(&p); build_restore_work_registers(&p);
#ifdef CONFIG_CPU_MICROMIPS
if ((unsigned long)tlb_do_page_fault_0 & 1) {
uasm_i_lui(&p, K0, uasm_rel_hi((long)tlb_do_page_fault_0));
uasm_i_addiu(&p, K0, K0, uasm_rel_lo((long)tlb_do_page_fault_0));
uasm_i_jr(&p, K0);
} else
#endif
uasm_i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff); uasm_i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff);
uasm_i_nop(&p); uasm_i_nop(&p);
...@@ -2077,6 +2157,13 @@ static void __cpuinit build_r4000_tlb_store_handler(void) ...@@ -2077,6 +2157,13 @@ static void __cpuinit build_r4000_tlb_store_handler(void)
uasm_l_nopage_tlbs(&l, p); uasm_l_nopage_tlbs(&l, p);
build_restore_work_registers(&p); build_restore_work_registers(&p);
#ifdef CONFIG_CPU_MICROMIPS
if ((unsigned long)tlb_do_page_fault_1 & 1) {
uasm_i_lui(&p, K0, uasm_rel_hi((long)tlb_do_page_fault_1));
uasm_i_addiu(&p, K0, K0, uasm_rel_lo((long)tlb_do_page_fault_1));
uasm_i_jr(&p, K0);
} else
#endif
uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff); uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
uasm_i_nop(&p); uasm_i_nop(&p);
...@@ -2125,6 +2212,13 @@ static void __cpuinit build_r4000_tlb_modify_handler(void) ...@@ -2125,6 +2212,13 @@ static void __cpuinit build_r4000_tlb_modify_handler(void)
uasm_l_nopage_tlbm(&l, p); uasm_l_nopage_tlbm(&l, p);
build_restore_work_registers(&p); build_restore_work_registers(&p);
#ifdef CONFIG_CPU_MICROMIPS
if ((unsigned long)tlb_do_page_fault_1 & 1) {
uasm_i_lui(&p, K0, uasm_rel_hi((long)tlb_do_page_fault_1));
uasm_i_addiu(&p, K0, K0, uasm_rel_lo((long)tlb_do_page_fault_1));
uasm_i_jr(&p, K0);
} else
#endif
uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff); uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
uasm_i_nop(&p); uasm_i_nop(&p);
...@@ -2162,6 +2256,7 @@ void __cpuinit build_tlb_refill_handler(void) ...@@ -2162,6 +2256,7 @@ void __cpuinit build_tlb_refill_handler(void)
case CPU_TX3922: case CPU_TX3922:
case CPU_TX3927: case CPU_TX3927:
#ifndef CONFIG_MIPS_PGD_C0_CONTEXT #ifndef CONFIG_MIPS_PGD_C0_CONTEXT
setup_asid(0x40, 0xfc0, 0xf000, ASID_FIRST_VERSION_R3000);
if (cpu_has_local_ebase) if (cpu_has_local_ebase)
build_r3000_tlb_refill_handler(); build_r3000_tlb_refill_handler();
if (!run_once) { if (!run_once) {
...@@ -2187,6 +2282,11 @@ void __cpuinit build_tlb_refill_handler(void) ...@@ -2187,6 +2282,11 @@ void __cpuinit build_tlb_refill_handler(void)
break; break;
default: default:
#ifndef CONFIG_MIPS_MT_SMTC
setup_asid(0x1, 0xff, 0xff00, ASID_FIRST_VERSION_R4000);
#else
setup_asid(0x1, smtc_asid_mask, 0xff00, ASID_FIRST_VERSION_R4000);
#endif
if (!run_once) { if (!run_once) {
scratch_reg = allocate_kscratch(); scratch_reg = allocate_kscratch();
#ifdef CONFIG_MIPS_PGD_C0_CONTEXT #ifdef CONFIG_MIPS_PGD_C0_CONTEXT
......
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* A small micro-assembler. It is intentionally kept simple, does only
* support a subset of instructions, and does not try to hide pipeline
* effects like branch delay slots.
*
* Copyright (C) 2004, 2005, 2006, 2008 Thiemo Seufer
* Copyright (C) 2005, 2007 Maciej W. Rozycki
* Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
* Copyright (C) 2012, 2013 MIPS Technologies, Inc. All rights reserved.
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
#include <asm/inst.h>
#include <asm/elf.h>
#include <asm/bugs.h>
#define UASM_ISA _UASM_ISA_MICROMIPS
#include <asm/uasm.h>
#define RS_MASK 0x1f
#define RS_SH 16
#define RT_MASK 0x1f
#define RT_SH 21
#define SCIMM_MASK 0x3ff
#define SCIMM_SH 16
/* This macro sets the non-variable bits of an instruction. */
#define M(a, b, c, d, e, f) \
((a) << OP_SH \
| (b) << RT_SH \
| (c) << RS_SH \
| (d) << RD_SH \
| (e) << RE_SH \
| (f) << FUNC_SH)
/* Define these when we are not the ISA the kernel is being compiled with. */
#ifndef CONFIG_CPU_MICROMIPS
#define MM_uasm_i_b(buf, off) ISAOPC(_beq)(buf, 0, 0, off)
#define MM_uasm_i_beqz(buf, rs, off) ISAOPC(_beq)(buf, rs, 0, off)
#define MM_uasm_i_beqzl(buf, rs, off) ISAOPC(_beql)(buf, rs, 0, off)
#define MM_uasm_i_bnez(buf, rs, off) ISAOPC(_bne)(buf, rs, 0, off)
#endif
#include "uasm.c"
static struct insn insn_table_MM[] __uasminitdata = {
{ insn_addu, M(mm_pool32a_op, 0, 0, 0, 0, mm_addu32_op), RT | RS | RD },
{ insn_addiu, M(mm_addiu32_op, 0, 0, 0, 0, 0), RT | RS | SIMM },
{ insn_and, M(mm_pool32a_op, 0, 0, 0, 0, mm_and_op), RT | RS | RD },
{ insn_andi, M(mm_andi32_op, 0, 0, 0, 0, 0), RT | RS | UIMM },
{ insn_beq, M(mm_beq32_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
{ insn_beql, 0, 0 },
{ insn_bgez, M(mm_pool32i_op, mm_bgez_op, 0, 0, 0, 0), RS | BIMM },
{ insn_bgezl, 0, 0 },
{ insn_bltz, M(mm_pool32i_op, mm_bltz_op, 0, 0, 0, 0), RS | BIMM },
{ insn_bltzl, 0, 0 },
{ insn_bne, M(mm_bne32_op, 0, 0, 0, 0, 0), RT | RS | BIMM },
{ insn_cache, M(mm_pool32b_op, 0, 0, mm_cache_func, 0, 0), RT | RS | SIMM },
{ insn_daddu, 0, 0 },
{ insn_daddiu, 0, 0 },
{ insn_dmfc0, 0, 0 },
{ insn_dmtc0, 0, 0 },
{ insn_dsll, 0, 0 },
{ insn_dsll32, 0, 0 },
{ insn_dsra, 0, 0 },
{ insn_dsrl, 0, 0 },
{ insn_dsrl32, 0, 0 },
{ insn_drotr, 0, 0 },
{ insn_drotr32, 0, 0 },
{ insn_dsubu, 0, 0 },
{ insn_eret, M(mm_pool32a_op, 0, 0, 0, mm_eret_op, mm_pool32axf_op), 0 },
{ insn_ins, M(mm_pool32a_op, 0, 0, 0, 0, mm_ins_op), RT | RS | RD | RE },
{ insn_ext, M(mm_pool32a_op, 0, 0, 0, 0, mm_ext_op), RT | RS | RD | RE },
{ insn_j, M(mm_j32_op, 0, 0, 0, 0, 0), JIMM },
{ insn_jal, M(mm_jal32_op, 0, 0, 0, 0, 0), JIMM },
{ insn_jr, M(mm_pool32a_op, 0, 0, 0, mm_jalr_op, mm_pool32axf_op), RS },
{ insn_ld, 0, 0 },
{ insn_ll, M(mm_pool32c_op, 0, 0, (mm_ll_func << 1), 0, 0), RS | RT | SIMM },
{ insn_lld, 0, 0 },
{ insn_lui, M(mm_pool32i_op, mm_lui_op, 0, 0, 0, 0), RS | SIMM },
{ insn_lw, M(mm_lw32_op, 0, 0, 0, 0, 0), RT | RS | SIMM },
{ insn_mfc0, M(mm_pool32a_op, 0, 0, 0, mm_mfc0_op, mm_pool32axf_op), RT | RS | RD },
{ insn_mtc0, M(mm_pool32a_op, 0, 0, 0, mm_mtc0_op, mm_pool32axf_op), RT | RS | RD },
{ insn_or, M(mm_pool32a_op, 0, 0, 0, 0, mm_or32_op), RT | RS | RD },
{ insn_ori, M(mm_ori32_op, 0, 0, 0, 0, 0), RT | RS | UIMM },
{ insn_pref, M(mm_pool32c_op, 0, 0, (mm_pref_func << 1), 0, 0), RT | RS | SIMM },
{ insn_rfe, 0, 0 },
{ insn_sc, M(mm_pool32c_op, 0, 0, (mm_sc_func << 1), 0, 0), RT | RS | SIMM },
{ insn_scd, 0, 0 },
{ insn_sd, 0, 0 },
{ insn_sll, M(mm_pool32a_op, 0, 0, 0, 0, mm_sll32_op), RT | RS | RD },
{ insn_sra, M(mm_pool32a_op, 0, 0, 0, 0, mm_sra_op), RT | RS | RD },
{ insn_srl, M(mm_pool32a_op, 0, 0, 0, 0, mm_srl32_op), RT | RS | RD },
{ insn_rotr, M(mm_pool32a_op, 0, 0, 0, 0, mm_rotr_op), RT | RS | RD },
{ insn_subu, M(mm_pool32a_op, 0, 0, 0, 0, mm_subu32_op), RT | RS | RD },
{ insn_sw, M(mm_sw32_op, 0, 0, 0, 0, 0), RT | RS | SIMM },
{ insn_tlbp, M(mm_pool32a_op, 0, 0, 0, mm_tlbp_op, mm_pool32axf_op), 0 },
{ insn_tlbr, M(mm_pool32a_op, 0, 0, 0, mm_tlbr_op, mm_pool32axf_op), 0 },
{ insn_tlbwi, M(mm_pool32a_op, 0, 0, 0, mm_tlbwi_op, mm_pool32axf_op), 0 },
{ insn_tlbwr, M(mm_pool32a_op, 0, 0, 0, mm_tlbwr_op, mm_pool32axf_op), 0 },
{ insn_xor, M(mm_pool32a_op, 0, 0, 0, 0, mm_xor32_op), RT | RS | RD },
{ insn_xori, M(mm_xori32_op, 0, 0, 0, 0, 0), RT | RS | UIMM },
{ insn_dins, 0, 0 },
{ insn_dinsm, 0, 0 },
{ insn_syscall, M(mm_pool32a_op, 0, 0, 0, mm_syscall_op, mm_pool32axf_op), SCIMM},
{ insn_bbit0, 0, 0 },
{ insn_bbit1, 0, 0 },
{ insn_lwx, 0, 0 },
{ insn_ldx, 0, 0 },
{ insn_invalid, 0, 0 }
};
#undef M
static inline __uasminit u32 build_bimm(s32 arg)
{
WARN(arg > 0xffff || arg < -0x10000,
KERN_WARNING "Micro-assembler field overflow\n");
WARN(arg & 0x3, KERN_WARNING "Invalid micro-assembler branch target\n");
return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 1) & 0x7fff);
}
static inline __uasminit u32 build_jimm(u32 arg)
{
WARN(arg & ~((JIMM_MASK << 2) | 1),
KERN_WARNING "Micro-assembler field overflow\n");
return (arg >> 1) & JIMM_MASK;
}
/*
* The order of opcode arguments is implicitly left to right,
* starting with RS and ending with FUNC or IMM.
*/
static void __uasminit build_insn(u32 **buf, enum opcode opc, ...)
{
struct insn *ip = NULL;
unsigned int i;
va_list ap;
u32 op;
for (i = 0; insn_table_MM[i].opcode != insn_invalid; i++)
if (insn_table_MM[i].opcode == opc) {
ip = &insn_table_MM[i];
break;
}
if (!ip || (opc == insn_daddiu && r4k_daddiu_bug()))
panic("Unsupported Micro-assembler instruction %d", opc);
op = ip->match;
va_start(ap, opc);
if (ip->fields & RS) {
if (opc == insn_mfc0 || opc == insn_mtc0)
op |= build_rt(va_arg(ap, u32));
else
op |= build_rs(va_arg(ap, u32));
}
if (ip->fields & RT) {
if (opc == insn_mfc0 || opc == insn_mtc0)
op |= build_rs(va_arg(ap, u32));
else
op |= build_rt(va_arg(ap, u32));
}
if (ip->fields & RD)
op |= build_rd(va_arg(ap, u32));
if (ip->fields & RE)
op |= build_re(va_arg(ap, u32));
if (ip->fields & SIMM)
op |= build_simm(va_arg(ap, s32));
if (ip->fields & UIMM)
op |= build_uimm(va_arg(ap, u32));
if (ip->fields & BIMM)
op |= build_bimm(va_arg(ap, s32));
if (ip->fields & JIMM)
op |= build_jimm(va_arg(ap, u32));
if (ip->fields & FUNC)
op |= build_func(va_arg(ap, u32));
if (ip->fields & SET)
op |= build_set(va_arg(ap, u32));
if (ip->fields & SCIMM)
op |= build_scimm(va_arg(ap, u32));
va_end(ap);
#ifdef CONFIG_CPU_LITTLE_ENDIAN
**buf = ((op & 0xffff) << 16) | (op >> 16);
#else
**buf = op;
#endif
(*buf)++;
}
static inline void __uasminit
__resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab)
{
long laddr = (long)lab->addr;
long raddr = (long)rel->addr;
switch (rel->type) {
case R_MIPS_PC16:
#ifdef CONFIG_CPU_LITTLE_ENDIAN
*rel->addr |= (build_bimm(laddr - (raddr + 4)) << 16);
#else
*rel->addr |= build_bimm(laddr - (raddr + 4));
#endif
break;
default:
panic("Unsupported Micro-assembler relocation %d",
rel->type);
}
}
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* A small micro-assembler. It is intentionally kept simple, does only
* support a subset of instructions, and does not try to hide pipeline
* effects like branch delay slots.
*
* Copyright (C) 2004, 2005, 2006, 2008 Thiemo Seufer
* Copyright (C) 2005, 2007 Maciej W. Rozycki
* Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
* Copyright (C) 2012, 2013 MIPS Technologies, Inc. All rights reserved.
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
#include <asm/inst.h>
#include <asm/elf.h>
#include <asm/bugs.h>
#define UASM_ISA _UASM_ISA_CLASSIC
#include <asm/uasm.h>
#define RS_MASK 0x1f
#define RS_SH 21
#define RT_MASK 0x1f
#define RT_SH 16
#define SCIMM_MASK 0xfffff
#define SCIMM_SH 6
/* This macro sets the non-variable bits of an instruction. */
#define M(a, b, c, d, e, f) \
((a) << OP_SH \
| (b) << RS_SH \
| (c) << RT_SH \
| (d) << RD_SH \
| (e) << RE_SH \
| (f) << FUNC_SH)
/* Define these when we are not the ISA the kernel is being compiled with. */
#ifdef CONFIG_CPU_MICROMIPS
#define CL_uasm_i_b(buf, off) ISAOPC(_beq)(buf, 0, 0, off)
#define CL_uasm_i_beqz(buf, rs, off) ISAOPC(_beq)(buf, rs, 0, off)
#define CL_uasm_i_beqzl(buf, rs, off) ISAOPC(_beql)(buf, rs, 0, off)
#define CL_uasm_i_bnez(buf, rs, off) ISAOPC(_bne)(buf, rs, 0, off)
#endif
#include "uasm.c"
static struct insn insn_table[] __uasminitdata = {
{ insn_addiu, M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_addu, M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD },
{ insn_andi, M(andi_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
{ insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD },
{ insn_bbit0, M(lwc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
{ insn_bbit1, M(swc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
{ insn_beql, M(beql_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
{ insn_beq, M(beq_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
{ insn_bgezl, M(bcond_op, 0, bgezl_op, 0, 0, 0), RS | BIMM },
{ insn_bgez, M(bcond_op, 0, bgez_op, 0, 0, 0), RS | BIMM },
{ insn_bltzl, M(bcond_op, 0, bltzl_op, 0, 0, 0), RS | BIMM },
{ insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM },
{ insn_bne, M(bne_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
{ insn_cache, M(cache_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_daddiu, M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD },
{ insn_dinsm, M(spec3_op, 0, 0, 0, 0, dinsm_op), RS | RT | RD | RE },
{ insn_dins, M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE },
{ insn_dmfc0, M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET},
{ insn_dmtc0, M(cop0_op, dmtc_op, 0, 0, 0, 0), RT | RD | SET},
{ insn_drotr32, M(spec_op, 1, 0, 0, 0, dsrl32_op), RT | RD | RE },
{ insn_drotr, M(spec_op, 1, 0, 0, 0, dsrl_op), RT | RD | RE },
{ insn_dsll32, M(spec_op, 0, 0, 0, 0, dsll32_op), RT | RD | RE },
{ insn_dsll, M(spec_op, 0, 0, 0, 0, dsll_op), RT | RD | RE },
{ insn_dsra, M(spec_op, 0, 0, 0, 0, dsra_op), RT | RD | RE },
{ insn_dsrl32, M(spec_op, 0, 0, 0, 0, dsrl32_op), RT | RD | RE },
{ insn_dsrl, M(spec_op, 0, 0, 0, 0, dsrl_op), RT | RD | RE },
{ insn_dsubu, M(spec_op, 0, 0, 0, 0, dsubu_op), RS | RT | RD },
{ insn_eret, M(cop0_op, cop_op, 0, 0, 0, eret_op), 0 },
{ insn_ext, M(spec3_op, 0, 0, 0, 0, ext_op), RS | RT | RD | RE },
{ insn_ins, M(spec3_op, 0, 0, 0, 0, ins_op), RS | RT | RD | RE },
{ insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM },
{ insn_jal, M(jal_op, 0, 0, 0, 0, 0), JIMM },
{ insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM },
{ insn_jr, M(spec_op, 0, 0, 0, 0, jr_op), RS },
{ insn_ld, M(ld_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_ldx, M(spec3_op, 0, 0, 0, ldx_op, lx_op), RS | RT | RD },
{ insn_lld, M(lld_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_ll, M(ll_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_lui, M(lui_op, 0, 0, 0, 0, 0), RT | SIMM },
{ insn_lw, M(lw_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_lwx, M(spec3_op, 0, 0, 0, lwx_op, lx_op), RS | RT | RD },
{ insn_mfc0, M(cop0_op, mfc_op, 0, 0, 0, 0), RT | RD | SET},
{ insn_mtc0, M(cop0_op, mtc_op, 0, 0, 0, 0), RT | RD | SET},
{ insn_ori, M(ori_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
{ insn_or, M(spec_op, 0, 0, 0, 0, or_op), RS | RT | RD },
{ insn_pref, M(pref_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_rfe, M(cop0_op, cop_op, 0, 0, 0, rfe_op), 0 },
{ insn_rotr, M(spec_op, 1, 0, 0, 0, srl_op), RT | RD | RE },
{ insn_scd, M(scd_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_sc, M(sc_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_sd, M(sd_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_sll, M(spec_op, 0, 0, 0, 0, sll_op), RT | RD | RE },
{ insn_sra, M(spec_op, 0, 0, 0, 0, sra_op), RT | RD | RE },
{ insn_srl, M(spec_op, 0, 0, 0, 0, srl_op), RT | RD | RE },
{ insn_subu, M(spec_op, 0, 0, 0, 0, subu_op), RS | RT | RD },
{ insn_sw, M(sw_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_syscall, M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM},
{ insn_tlbp, M(cop0_op, cop_op, 0, 0, 0, tlbp_op), 0 },
{ insn_tlbr, M(cop0_op, cop_op, 0, 0, 0, tlbr_op), 0 },
{ insn_tlbwi, M(cop0_op, cop_op, 0, 0, 0, tlbwi_op), 0 },
{ insn_tlbwr, M(cop0_op, cop_op, 0, 0, 0, tlbwr_op), 0 },
{ insn_xori, M(xori_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
{ insn_xor, M(spec_op, 0, 0, 0, 0, xor_op), RS | RT | RD },
{ insn_invalid, 0, 0 }
};
#undef M
static inline __uasminit u32 build_bimm(s32 arg)
{
WARN(arg > 0x1ffff || arg < -0x20000,
KERN_WARNING "Micro-assembler field overflow\n");
WARN(arg & 0x3, KERN_WARNING "Invalid micro-assembler branch target\n");
return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 2) & 0x7fff);
}
static inline __uasminit u32 build_jimm(u32 arg)
{
WARN(arg & ~(JIMM_MASK << 2),
KERN_WARNING "Micro-assembler field overflow\n");
return (arg >> 2) & JIMM_MASK;
}
/*
* The order of opcode arguments is implicitly left to right,
* starting with RS and ending with FUNC or IMM.
*/
static void __uasminit build_insn(u32 **buf, enum opcode opc, ...)
{
struct insn *ip = NULL;
unsigned int i;
va_list ap;
u32 op;
for (i = 0; insn_table[i].opcode != insn_invalid; i++)
if (insn_table[i].opcode == opc) {
ip = &insn_table[i];
break;
}
if (!ip || (opc == insn_daddiu && r4k_daddiu_bug()))
panic("Unsupported Micro-assembler instruction %d", opc);
op = ip->match;
va_start(ap, opc);
if (ip->fields & RS)
op |= build_rs(va_arg(ap, u32));
if (ip->fields & RT)
op |= build_rt(va_arg(ap, u32));
if (ip->fields & RD)
op |= build_rd(va_arg(ap, u32));
if (ip->fields & RE)
op |= build_re(va_arg(ap, u32));
if (ip->fields & SIMM)
op |= build_simm(va_arg(ap, s32));
if (ip->fields & UIMM)
op |= build_uimm(va_arg(ap, u32));
if (ip->fields & BIMM)
op |= build_bimm(va_arg(ap, s32));
if (ip->fields & JIMM)
op |= build_jimm(va_arg(ap, u32));
if (ip->fields & FUNC)
op |= build_func(va_arg(ap, u32));
if (ip->fields & SET)
op |= build_set(va_arg(ap, u32));
if (ip->fields & SCIMM)
op |= build_scimm(va_arg(ap, u32));
va_end(ap);
**buf = op;
(*buf)++;
}
static inline void __uasminit
__resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab)
{
long laddr = (long)lab->addr;
long raddr = (long)rel->addr;
switch (rel->type) {
case R_MIPS_PC16:
*rel->addr |= build_bimm(laddr - (raddr + 4));
break;
default:
panic("Unsupported Micro-assembler relocation %d",
rel->type);
}
}
...@@ -10,17 +10,9 @@ ...@@ -10,17 +10,9 @@
* Copyright (C) 2004, 2005, 2006, 2008 Thiemo Seufer * Copyright (C) 2004, 2005, 2006, 2008 Thiemo Seufer
* Copyright (C) 2005, 2007 Maciej W. Rozycki * Copyright (C) 2005, 2007 Maciej W. Rozycki
* Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org) * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
* Copyright (C) 2012, 2013 MIPS Technologies, Inc. All rights reserved.
*/ */
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
#include <asm/inst.h>
#include <asm/elf.h>
#include <asm/bugs.h>
#include <asm/uasm.h>
enum fields { enum fields {
RS = 0x001, RS = 0x001,
RT = 0x002, RT = 0x002,
...@@ -37,10 +29,6 @@ enum fields { ...@@ -37,10 +29,6 @@ enum fields {
#define OP_MASK 0x3f #define OP_MASK 0x3f
#define OP_SH 26 #define OP_SH 26
#define RS_MASK 0x1f
#define RS_SH 21
#define RT_MASK 0x1f
#define RT_SH 16
#define RD_MASK 0x1f #define RD_MASK 0x1f
#define RD_SH 11 #define RD_SH 11
#define RE_MASK 0x1f #define RE_MASK 0x1f
...@@ -53,8 +41,6 @@ enum fields { ...@@ -53,8 +41,6 @@ enum fields {
#define FUNC_SH 0 #define FUNC_SH 0
#define SET_MASK 0x7 #define SET_MASK 0x7
#define SET_SH 0 #define SET_SH 0
#define SCIMM_MASK 0xfffff
#define SCIMM_SH 6
enum opcode { enum opcode {
insn_invalid, insn_invalid,
...@@ -77,85 +63,6 @@ struct insn { ...@@ -77,85 +63,6 @@ struct insn {
enum fields fields; enum fields fields;
}; };
/* This macro sets the non-variable bits of an instruction. */
#define M(a, b, c, d, e, f) \
((a) << OP_SH \
| (b) << RS_SH \
| (c) << RT_SH \
| (d) << RD_SH \
| (e) << RE_SH \
| (f) << FUNC_SH)
static struct insn insn_table[] __uasminitdata = {
{ insn_addiu, M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_addu, M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD },
{ insn_andi, M(andi_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
{ insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD },
{ insn_bbit0, M(lwc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
{ insn_bbit1, M(swc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
{ insn_beql, M(beql_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
{ insn_beq, M(beq_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
{ insn_bgezl, M(bcond_op, 0, bgezl_op, 0, 0, 0), RS | BIMM },
{ insn_bgez, M(bcond_op, 0, bgez_op, 0, 0, 0), RS | BIMM },
{ insn_bltzl, M(bcond_op, 0, bltzl_op, 0, 0, 0), RS | BIMM },
{ insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM },
{ insn_bne, M(bne_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
{ insn_cache, M(cache_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_daddiu, M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD },
{ insn_dinsm, M(spec3_op, 0, 0, 0, 0, dinsm_op), RS | RT | RD | RE },
{ insn_dins, M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE },
{ insn_dmfc0, M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET},
{ insn_dmtc0, M(cop0_op, dmtc_op, 0, 0, 0, 0), RT | RD | SET},
{ insn_drotr32, M(spec_op, 1, 0, 0, 0, dsrl32_op), RT | RD | RE },
{ insn_drotr, M(spec_op, 1, 0, 0, 0, dsrl_op), RT | RD | RE },
{ insn_dsll32, M(spec_op, 0, 0, 0, 0, dsll32_op), RT | RD | RE },
{ insn_dsll, M(spec_op, 0, 0, 0, 0, dsll_op), RT | RD | RE },
{ insn_dsra, M(spec_op, 0, 0, 0, 0, dsra_op), RT | RD | RE },
{ insn_dsrl32, M(spec_op, 0, 0, 0, 0, dsrl32_op), RT | RD | RE },
{ insn_dsrl, M(spec_op, 0, 0, 0, 0, dsrl_op), RT | RD | RE },
{ insn_dsubu, M(spec_op, 0, 0, 0, 0, dsubu_op), RS | RT | RD },
{ insn_eret, M(cop0_op, cop_op, 0, 0, 0, eret_op), 0 },
{ insn_ext, M(spec3_op, 0, 0, 0, 0, ext_op), RS | RT | RD | RE },
{ insn_ins, M(spec3_op, 0, 0, 0, 0, ins_op), RS | RT | RD | RE },
{ insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM },
{ insn_jal, M(jal_op, 0, 0, 0, 0, 0), JIMM },
{ insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM },
{ insn_jr, M(spec_op, 0, 0, 0, 0, jr_op), RS },
{ insn_ld, M(ld_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_ldx, M(spec3_op, 0, 0, 0, ldx_op, lx_op), RS | RT | RD },
{ insn_lld, M(lld_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_ll, M(ll_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_lui, M(lui_op, 0, 0, 0, 0, 0), RT | SIMM },
{ insn_lw, M(lw_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_lwx, M(spec3_op, 0, 0, 0, lwx_op, lx_op), RS | RT | RD },
{ insn_mfc0, M(cop0_op, mfc_op, 0, 0, 0, 0), RT | RD | SET},
{ insn_mtc0, M(cop0_op, mtc_op, 0, 0, 0, 0), RT | RD | SET},
{ insn_ori, M(ori_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
{ insn_or, M(spec_op, 0, 0, 0, 0, or_op), RS | RT | RD },
{ insn_pref, M(pref_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_rfe, M(cop0_op, cop_op, 0, 0, 0, rfe_op), 0 },
{ insn_rotr, M(spec_op, 1, 0, 0, 0, srl_op), RT | RD | RE },
{ insn_scd, M(scd_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_sc, M(sc_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_sd, M(sd_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_sll, M(spec_op, 0, 0, 0, 0, sll_op), RT | RD | RE },
{ insn_sra, M(spec_op, 0, 0, 0, 0, sra_op), RT | RD | RE },
{ insn_srl, M(spec_op, 0, 0, 0, 0, srl_op), RT | RD | RE },
{ insn_subu, M(spec_op, 0, 0, 0, 0, subu_op), RS | RT | RD },
{ insn_sw, M(sw_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_syscall, M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM},
{ insn_tlbp, M(cop0_op, cop_op, 0, 0, 0, tlbp_op), 0 },
{ insn_tlbr, M(cop0_op, cop_op, 0, 0, 0, tlbr_op), 0 },
{ insn_tlbwi, M(cop0_op, cop_op, 0, 0, 0, tlbwi_op), 0 },
{ insn_tlbwr, M(cop0_op, cop_op, 0, 0, 0, tlbwr_op), 0 },
{ insn_xori, M(xori_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
{ insn_xor, M(spec_op, 0, 0, 0, 0, xor_op), RS | RT | RD },
{ insn_invalid, 0, 0 }
};
#undef M
static inline __uasminit u32 build_rs(u32 arg) static inline __uasminit u32 build_rs(u32 arg)
{ {
WARN(arg & ~RS_MASK, KERN_WARNING "Micro-assembler field overflow\n"); WARN(arg & ~RS_MASK, KERN_WARNING "Micro-assembler field overflow\n");
...@@ -199,24 +106,6 @@ static inline __uasminit u32 build_uimm(u32 arg) ...@@ -199,24 +106,6 @@ static inline __uasminit u32 build_uimm(u32 arg)
return arg & IMM_MASK; return arg & IMM_MASK;
} }
static inline __uasminit u32 build_bimm(s32 arg)
{
WARN(arg > 0x1ffff || arg < -0x20000,
KERN_WARNING "Micro-assembler field overflow\n");
WARN(arg & 0x3, KERN_WARNING "Invalid micro-assembler branch target\n");
return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 2) & 0x7fff);
}
static inline __uasminit u32 build_jimm(u32 arg)
{
WARN(arg & ~(JIMM_MASK << 2),
KERN_WARNING "Micro-assembler field overflow\n");
return (arg >> 2) & JIMM_MASK;
}
static inline __uasminit u32 build_scimm(u32 arg) static inline __uasminit u32 build_scimm(u32 arg)
{ {
WARN(arg & ~SCIMM_MASK, WARN(arg & ~SCIMM_MASK,
...@@ -239,55 +128,7 @@ static inline __uasminit u32 build_set(u32 arg) ...@@ -239,55 +128,7 @@ static inline __uasminit u32 build_set(u32 arg)
return arg & SET_MASK; return arg & SET_MASK;
} }
/* static void __uasminit build_insn(u32 **buf, enum opcode opc, ...);
* The order of opcode arguments is implicitly left to right,
* starting with RS and ending with FUNC or IMM.
*/
static void __uasminit build_insn(u32 **buf, enum opcode opc, ...)
{
struct insn *ip = NULL;
unsigned int i;
va_list ap;
u32 op;
for (i = 0; insn_table[i].opcode != insn_invalid; i++)
if (insn_table[i].opcode == opc) {
ip = &insn_table[i];
break;
}
if (!ip || (opc == insn_daddiu && r4k_daddiu_bug()))
panic("Unsupported Micro-assembler instruction %d", opc);
op = ip->match;
va_start(ap, opc);
if (ip->fields & RS)
op |= build_rs(va_arg(ap, u32));
if (ip->fields & RT)
op |= build_rt(va_arg(ap, u32));
if (ip->fields & RD)
op |= build_rd(va_arg(ap, u32));
if (ip->fields & RE)
op |= build_re(va_arg(ap, u32));
if (ip->fields & SIMM)
op |= build_simm(va_arg(ap, s32));
if (ip->fields & UIMM)
op |= build_uimm(va_arg(ap, u32));
if (ip->fields & BIMM)
op |= build_bimm(va_arg(ap, s32));
if (ip->fields & JIMM)
op |= build_jimm(va_arg(ap, u32));
if (ip->fields & FUNC)
op |= build_func(va_arg(ap, u32));
if (ip->fields & SET)
op |= build_set(va_arg(ap, u32));
if (ip->fields & SCIMM)
op |= build_scimm(va_arg(ap, u32));
va_end(ap);
**buf = op;
(*buf)++;
}
#define I_u1u2u3(op) \ #define I_u1u2u3(op) \
Ip_u1u2u3(op) \ Ip_u1u2u3(op) \
...@@ -445,7 +286,7 @@ I_u3u1u2(_ldx) ...@@ -445,7 +286,7 @@ I_u3u1u2(_ldx)
#ifdef CONFIG_CPU_CAVIUM_OCTEON #ifdef CONFIG_CPU_CAVIUM_OCTEON
#include <asm/octeon/octeon.h> #include <asm/octeon/octeon.h>
void __uasminit uasm_i_pref(u32 **buf, unsigned int a, signed int b, void __uasminit ISAFUNC(uasm_i_pref)(u32 **buf, unsigned int a, signed int b,
unsigned int c) unsigned int c)
{ {
if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) && a <= 24 && a != 5) if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) && a <= 24 && a != 5)
...@@ -457,21 +298,21 @@ void __uasminit uasm_i_pref(u32 **buf, unsigned int a, signed int b, ...@@ -457,21 +298,21 @@ void __uasminit uasm_i_pref(u32 **buf, unsigned int a, signed int b,
else else
build_insn(buf, insn_pref, c, a, b); build_insn(buf, insn_pref, c, a, b);
} }
UASM_EXPORT_SYMBOL(uasm_i_pref); UASM_EXPORT_SYMBOL(ISAFUNC(uasm_i_pref));
#else #else
I_u2s3u1(_pref) I_u2s3u1(_pref)
#endif #endif
/* Handle labels. */ /* Handle labels. */
void __uasminit uasm_build_label(struct uasm_label **lab, u32 *addr, int lid) void __uasminit ISAFUNC(uasm_build_label)(struct uasm_label **lab, u32 *addr, int lid)
{ {
(*lab)->addr = addr; (*lab)->addr = addr;
(*lab)->lab = lid; (*lab)->lab = lid;
(*lab)++; (*lab)++;
} }
UASM_EXPORT_SYMBOL(uasm_build_label); UASM_EXPORT_SYMBOL(ISAFUNC(uasm_build_label));
int __uasminit uasm_in_compat_space_p(long addr) int __uasminit ISAFUNC(uasm_in_compat_space_p)(long addr)
{ {
/* Is this address in 32bit compat space? */ /* Is this address in 32bit compat space? */
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
...@@ -480,7 +321,7 @@ int __uasminit uasm_in_compat_space_p(long addr) ...@@ -480,7 +321,7 @@ int __uasminit uasm_in_compat_space_p(long addr)
return 1; return 1;
#endif #endif
} }
UASM_EXPORT_SYMBOL(uasm_in_compat_space_p); UASM_EXPORT_SYMBOL(ISAFUNC(uasm_in_compat_space_p));
static int __uasminit uasm_rel_highest(long val) static int __uasminit uasm_rel_highest(long val)
{ {
...@@ -500,77 +341,66 @@ static int __uasminit uasm_rel_higher(long val) ...@@ -500,77 +341,66 @@ static int __uasminit uasm_rel_higher(long val)
#endif #endif
} }
int __uasminit uasm_rel_hi(long val) int __uasminit ISAFUNC(uasm_rel_hi)(long val)
{ {
return ((((val + 0x8000L) >> 16) & 0xffff) ^ 0x8000) - 0x8000; return ((((val + 0x8000L) >> 16) & 0xffff) ^ 0x8000) - 0x8000;
} }
UASM_EXPORT_SYMBOL(uasm_rel_hi); UASM_EXPORT_SYMBOL(ISAFUNC(uasm_rel_hi));
int __uasminit uasm_rel_lo(long val) int __uasminit ISAFUNC(uasm_rel_lo)(long val)
{ {
return ((val & 0xffff) ^ 0x8000) - 0x8000; return ((val & 0xffff) ^ 0x8000) - 0x8000;
} }
UASM_EXPORT_SYMBOL(uasm_rel_lo); UASM_EXPORT_SYMBOL(ISAFUNC(uasm_rel_lo));
void __uasminit UASM_i_LA_mostly(u32 **buf, unsigned int rs, long addr) void __uasminit ISAFUNC(UASM_i_LA_mostly)(u32 **buf, unsigned int rs, long addr)
{ {
if (!uasm_in_compat_space_p(addr)) { if (!ISAFUNC(uasm_in_compat_space_p)(addr)) {
uasm_i_lui(buf, rs, uasm_rel_highest(addr)); ISAFUNC(uasm_i_lui)(buf, rs, uasm_rel_highest(addr));
if (uasm_rel_higher(addr)) if (uasm_rel_higher(addr))
uasm_i_daddiu(buf, rs, rs, uasm_rel_higher(addr)); ISAFUNC(uasm_i_daddiu)(buf, rs, rs, uasm_rel_higher(addr));
if (uasm_rel_hi(addr)) { if (ISAFUNC(uasm_rel_hi(addr))) {
uasm_i_dsll(buf, rs, rs, 16); ISAFUNC(uasm_i_dsll)(buf, rs, rs, 16);
uasm_i_daddiu(buf, rs, rs, uasm_rel_hi(addr)); ISAFUNC(uasm_i_daddiu)(buf, rs, rs,
uasm_i_dsll(buf, rs, rs, 16); ISAFUNC(uasm_rel_hi)(addr));
ISAFUNC(uasm_i_dsll)(buf, rs, rs, 16);
} else } else
uasm_i_dsll32(buf, rs, rs, 0); ISAFUNC(uasm_i_dsll32)(buf, rs, rs, 0);
} else } else
uasm_i_lui(buf, rs, uasm_rel_hi(addr)); ISAFUNC(uasm_i_lui)(buf, rs, ISAFUNC(uasm_rel_hi(addr)));
} }
UASM_EXPORT_SYMBOL(UASM_i_LA_mostly); UASM_EXPORT_SYMBOL(ISAFUNC(UASM_i_LA_mostly));
void __uasminit UASM_i_LA(u32 **buf, unsigned int rs, long addr) void __uasminit ISAFUNC(UASM_i_LA)(u32 **buf, unsigned int rs, long addr)
{ {
UASM_i_LA_mostly(buf, rs, addr); ISAFUNC(UASM_i_LA_mostly)(buf, rs, addr);
if (uasm_rel_lo(addr)) { if (ISAFUNC(uasm_rel_lo(addr))) {
if (!uasm_in_compat_space_p(addr)) if (!ISAFUNC(uasm_in_compat_space_p)(addr))
uasm_i_daddiu(buf, rs, rs, uasm_rel_lo(addr)); ISAFUNC(uasm_i_daddiu)(buf, rs, rs,
ISAFUNC(uasm_rel_lo(addr)));
else else
uasm_i_addiu(buf, rs, rs, uasm_rel_lo(addr)); ISAFUNC(uasm_i_addiu)(buf, rs, rs,
ISAFUNC(uasm_rel_lo(addr)));
} }
} }
UASM_EXPORT_SYMBOL(UASM_i_LA); UASM_EXPORT_SYMBOL(ISAFUNC(UASM_i_LA));
/* Handle relocations. */ /* Handle relocations. */
void __uasminit void __uasminit
uasm_r_mips_pc16(struct uasm_reloc **rel, u32 *addr, int lid) ISAFUNC(uasm_r_mips_pc16)(struct uasm_reloc **rel, u32 *addr, int lid)
{ {
(*rel)->addr = addr; (*rel)->addr = addr;
(*rel)->type = R_MIPS_PC16; (*rel)->type = R_MIPS_PC16;
(*rel)->lab = lid; (*rel)->lab = lid;
(*rel)++; (*rel)++;
} }
UASM_EXPORT_SYMBOL(uasm_r_mips_pc16); UASM_EXPORT_SYMBOL(ISAFUNC(uasm_r_mips_pc16));
static inline void __uasminit static inline void __uasminit
__resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab) __resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab);
{
long laddr = (long)lab->addr;
long raddr = (long)rel->addr;
switch (rel->type) {
case R_MIPS_PC16:
*rel->addr |= build_bimm(laddr - (raddr + 4));
break;
default:
panic("Unsupported Micro-assembler relocation %d",
rel->type);
}
}
void __uasminit void __uasminit
uasm_resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab) ISAFUNC(uasm_resolve_relocs)(struct uasm_reloc *rel, struct uasm_label *lab)
{ {
struct uasm_label *l; struct uasm_label *l;
...@@ -579,40 +409,40 @@ uasm_resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab) ...@@ -579,40 +409,40 @@ uasm_resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab)
if (rel->lab == l->lab) if (rel->lab == l->lab)
__resolve_relocs(rel, l); __resolve_relocs(rel, l);
} }
UASM_EXPORT_SYMBOL(uasm_resolve_relocs); UASM_EXPORT_SYMBOL(ISAFUNC(uasm_resolve_relocs));
void __uasminit void __uasminit
uasm_move_relocs(struct uasm_reloc *rel, u32 *first, u32 *end, long off) ISAFUNC(uasm_move_relocs)(struct uasm_reloc *rel, u32 *first, u32 *end, long off)
{ {
for (; rel->lab != UASM_LABEL_INVALID; rel++) for (; rel->lab != UASM_LABEL_INVALID; rel++)
if (rel->addr >= first && rel->addr < end) if (rel->addr >= first && rel->addr < end)
rel->addr += off; rel->addr += off;
} }
UASM_EXPORT_SYMBOL(uasm_move_relocs); UASM_EXPORT_SYMBOL(ISAFUNC(uasm_move_relocs));
void __uasminit void __uasminit
uasm_move_labels(struct uasm_label *lab, u32 *first, u32 *end, long off) ISAFUNC(uasm_move_labels)(struct uasm_label *lab, u32 *first, u32 *end, long off)
{ {
for (; lab->lab != UASM_LABEL_INVALID; lab++) for (; lab->lab != UASM_LABEL_INVALID; lab++)
if (lab->addr >= first && lab->addr < end) if (lab->addr >= first && lab->addr < end)
lab->addr += off; lab->addr += off;
} }
UASM_EXPORT_SYMBOL(uasm_move_labels); UASM_EXPORT_SYMBOL(ISAFUNC(uasm_move_labels));
void __uasminit void __uasminit
uasm_copy_handler(struct uasm_reloc *rel, struct uasm_label *lab, u32 *first, ISAFUNC(uasm_copy_handler)(struct uasm_reloc *rel, struct uasm_label *lab, u32 *first,
u32 *end, u32 *target) u32 *end, u32 *target)
{ {
long off = (long)(target - first); long off = (long)(target - first);
memcpy(target, first, (end - first) * sizeof(u32)); memcpy(target, first, (end - first) * sizeof(u32));
uasm_move_relocs(rel, first, end, off); ISAFUNC(uasm_move_relocs(rel, first, end, off));
uasm_move_labels(lab, first, end, off); ISAFUNC(uasm_move_labels(lab, first, end, off));
} }
UASM_EXPORT_SYMBOL(uasm_copy_handler); UASM_EXPORT_SYMBOL(ISAFUNC(uasm_copy_handler));
int __uasminit uasm_insn_has_bdelay(struct uasm_reloc *rel, u32 *addr) int __uasminit ISAFUNC(uasm_insn_has_bdelay)(struct uasm_reloc *rel, u32 *addr)
{ {
for (; rel->lab != UASM_LABEL_INVALID; rel++) { for (; rel->lab != UASM_LABEL_INVALID; rel++) {
if (rel->addr == addr if (rel->addr == addr
...@@ -623,88 +453,88 @@ int __uasminit uasm_insn_has_bdelay(struct uasm_reloc *rel, u32 *addr) ...@@ -623,88 +453,88 @@ int __uasminit uasm_insn_has_bdelay(struct uasm_reloc *rel, u32 *addr)
return 0; return 0;
} }
UASM_EXPORT_SYMBOL(uasm_insn_has_bdelay); UASM_EXPORT_SYMBOL(ISAFUNC(uasm_insn_has_bdelay));
/* Convenience functions for labeled branches. */ /* Convenience functions for labeled branches. */
void __uasminit void __uasminit
uasm_il_bltz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid) ISAFUNC(uasm_il_bltz)(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
{ {
uasm_r_mips_pc16(r, *p, lid); uasm_r_mips_pc16(r, *p, lid);
uasm_i_bltz(p, reg, 0); ISAFUNC(uasm_i_bltz)(p, reg, 0);
} }
UASM_EXPORT_SYMBOL(uasm_il_bltz); UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bltz));
void __uasminit void __uasminit
uasm_il_b(u32 **p, struct uasm_reloc **r, int lid) ISAFUNC(uasm_il_b)(u32 **p, struct uasm_reloc **r, int lid)
{ {
uasm_r_mips_pc16(r, *p, lid); uasm_r_mips_pc16(r, *p, lid);
uasm_i_b(p, 0); ISAFUNC(uasm_i_b)(p, 0);
} }
UASM_EXPORT_SYMBOL(uasm_il_b); UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_b));
void __uasminit void __uasminit
uasm_il_beqz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid) ISAFUNC(uasm_il_beqz)(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
{ {
uasm_r_mips_pc16(r, *p, lid); uasm_r_mips_pc16(r, *p, lid);
uasm_i_beqz(p, reg, 0); ISAFUNC(uasm_i_beqz)(p, reg, 0);
} }
UASM_EXPORT_SYMBOL(uasm_il_beqz); UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_beqz));
void __uasminit void __uasminit
uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid) ISAFUNC(uasm_il_beqzl)(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
{ {
uasm_r_mips_pc16(r, *p, lid); uasm_r_mips_pc16(r, *p, lid);
uasm_i_beqzl(p, reg, 0); ISAFUNC(uasm_i_beqzl)(p, reg, 0);
} }
UASM_EXPORT_SYMBOL(uasm_il_beqzl); UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_beqzl));
void __uasminit void __uasminit
uasm_il_bne(u32 **p, struct uasm_reloc **r, unsigned int reg1, ISAFUNC(uasm_il_bne)(u32 **p, struct uasm_reloc **r, unsigned int reg1,
unsigned int reg2, int lid) unsigned int reg2, int lid)
{ {
uasm_r_mips_pc16(r, *p, lid); uasm_r_mips_pc16(r, *p, lid);
uasm_i_bne(p, reg1, reg2, 0); ISAFUNC(uasm_i_bne)(p, reg1, reg2, 0);
} }
UASM_EXPORT_SYMBOL(uasm_il_bne); UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bne));
void __uasminit void __uasminit
uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid) ISAFUNC(uasm_il_bnez)(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
{ {
uasm_r_mips_pc16(r, *p, lid); uasm_r_mips_pc16(r, *p, lid);
uasm_i_bnez(p, reg, 0); ISAFUNC(uasm_i_bnez)(p, reg, 0);
} }
UASM_EXPORT_SYMBOL(uasm_il_bnez); UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bnez));
void __uasminit void __uasminit
uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid) ISAFUNC(uasm_il_bgezl)(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
{ {
uasm_r_mips_pc16(r, *p, lid); uasm_r_mips_pc16(r, *p, lid);
uasm_i_bgezl(p, reg, 0); ISAFUNC(uasm_i_bgezl)(p, reg, 0);
} }
UASM_EXPORT_SYMBOL(uasm_il_bgezl); UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bgezl));
void __uasminit void __uasminit
uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid) ISAFUNC(uasm_il_bgez)(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
{ {
uasm_r_mips_pc16(r, *p, lid); uasm_r_mips_pc16(r, *p, lid);
uasm_i_bgez(p, reg, 0); ISAFUNC(uasm_i_bgez)(p, reg, 0);
} }
UASM_EXPORT_SYMBOL(uasm_il_bgez); UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bgez));
void __uasminit void __uasminit
uasm_il_bbit0(u32 **p, struct uasm_reloc **r, unsigned int reg, ISAFUNC(uasm_il_bbit0)(u32 **p, struct uasm_reloc **r, unsigned int reg,
unsigned int bit, int lid) unsigned int bit, int lid)
{ {
uasm_r_mips_pc16(r, *p, lid); uasm_r_mips_pc16(r, *p, lid);
uasm_i_bbit0(p, reg, bit, 0); ISAFUNC(uasm_i_bbit0)(p, reg, bit, 0);
} }
UASM_EXPORT_SYMBOL(uasm_il_bbit0); UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bbit0));
void __uasminit void __uasminit
uasm_il_bbit1(u32 **p, struct uasm_reloc **r, unsigned int reg, ISAFUNC(uasm_il_bbit1)(u32 **p, struct uasm_reloc **r, unsigned int reg,
unsigned int bit, int lid) unsigned int bit, int lid)
{ {
uasm_r_mips_pc16(r, *p, lid); uasm_r_mips_pc16(r, *p, lid);
uasm_i_bbit1(p, reg, bit, 0); ISAFUNC(uasm_i_bbit1)(p, reg, bit, 0);
} }
UASM_EXPORT_SYMBOL(uasm_il_bbit1); UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bbit1));
...@@ -5,9 +5,8 @@ ...@@ -5,9 +5,8 @@
# Copyright (C) 2008 Wind River Systems, Inc. # Copyright (C) 2008 Wind River Systems, Inc.
# written by Ralf Baechle <ralf@linux-mips.org> # written by Ralf Baechle <ralf@linux-mips.org>
# #
obj-y := malta-amon.o malta-cmdline.o \ obj-y := malta-amon.o malta-display.o malta-init.o \
malta-display.o malta-init.o malta-int.o \ malta-int.o malta-memory.o malta-platform.o \
malta-memory.o malta-platform.o \
malta-reset.o malta-setup.o malta-time.o malta-reset.o malta-setup.o malta-time.o
obj-$(CONFIG_EARLY_PRINTK) += malta-console.o obj-$(CONFIG_EARLY_PRINTK) += malta-console.o
......
/*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
* Kernel command line creation using the prom monitor (YAMON) argc/argv.
*/
#include <linux/init.h>
#include <linux/string.h>
#include <asm/bootinfo.h>
extern int prom_argc;
extern int *_prom_argv;
/*
* YAMON (32-bit PROM) pass arguments and environment as 32-bit pointer.
* This macro take care of sign extension.
*/
#define prom_argv(index) ((char *)(long)_prom_argv[(index)])
char * __init prom_getcmdline(void)
{
return &(arcs_cmdline[0]);
}
void __init prom_init_cmdline(void)
{
char *cp;
int actr;
actr = 1; /* Always ignore argv[0] */
cp = &(arcs_cmdline[0]);
while(actr < prom_argc) {
strcpy(cp, prom_argv(actr));
cp += strlen(prom_argv(actr));
*cp++ = ' ';
actr++;
}
if (cp != &(arcs_cmdline[0])) {
/* get rid of trailing space */
--cp;
*cp = '\0';
}
}
/* /*
* Carsten Langgaard, carstenl@mips.com * This file is subject to the terms and conditions of the GNU General Public
* Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. * License. See the file "COPYING" in the main directory of this archive
* * for more details.
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
* *
* Display routines for display messages in MIPS boards ascii display. * Display routines for display messages in MIPS boards ascii display.
*
* Copyright (C) 1999,2000,2012 MIPS Technologies, Inc.
* All rights reserved.
* Authors: Carsten Langgaard <carstenl@mips.com>
* Steven J. Hill <sjhill@mips.com>
*/ */
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <asm/io.h> #include <linux/io.h>
#include <asm/mips-boards/generic.h> #include <asm/mips-boards/generic.h>
#include <asm/mips-boards/prom.h>
extern const char display_string[]; extern const char display_string[];
static unsigned int display_count; static unsigned int display_count;
...@@ -36,11 +28,11 @@ void mips_display_message(const char *str) ...@@ -36,11 +28,11 @@ void mips_display_message(const char *str)
if (unlikely(display == NULL)) if (unlikely(display == NULL))
display = ioremap(ASCII_DISPLAY_POS_BASE, 16*sizeof(int)); display = ioremap(ASCII_DISPLAY_POS_BASE, 16*sizeof(int));
for (i = 0; i <= 14; i=i+2) { for (i = 0; i <= 14; i += 2) {
if (*str) if (*str)
__raw_writel(*str++, display + i); __raw_writel(*str++, display + i);
else else
__raw_writel(' ', display + i); __raw_writel(' ', display + i);
} }
} }
......
/* /*
* Copyright (C) 1999, 2000, 2004, 2005 MIPS Technologies, Inc. * This file is subject to the terms and conditions of the GNU General Public
* All rights reserved. * License. See the file "COPYING" in the main directory of this archive
* Authors: Carsten Langgaard <carstenl@mips.com> * for more details.
* Maciej W. Rozycki <macro@mips.com>
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
* *
* PROM library initialisation code. * PROM library initialisation code.
*
* Copyright (C) 1999,2000,2004,2005,2012 MIPS Technologies, Inc.
* All rights reserved.
* Authors: Carsten Langgaard <carstenl@mips.com>
* Maciej W. Rozycki <macro@mips.com>
* Steven J. Hill <sjhill@mips.com>
*/ */
#include <linux/init.h> #include <linux/init.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <asm/bootinfo.h>
#include <asm/gt64120.h>
#include <asm/io.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/smp-ops.h> #include <asm/smp-ops.h>
#include <asm/traps.h> #include <asm/traps.h>
#include <asm/fw/fw.h>
#include <asm/gcmpregs.h> #include <asm/gcmpregs.h>
#include <asm/mips-boards/prom.h>
#include <asm/mips-boards/generic.h> #include <asm/mips-boards/generic.h>
#include <asm/mips-boards/bonito64.h>
#include <asm/mips-boards/msc01_pci.h>
#include <asm/mips-boards/malta.h> #include <asm/mips-boards/malta.h>
int prom_argc;
int *_prom_argv, *_prom_envp;
/*
* YAMON (32-bit PROM) pass arguments and environment as 32-bit pointer.
* This macro take care of sign extension, if running in 64-bit mode.
*/
#define prom_envp(index) ((char *)(long)_prom_envp[(index)])
int init_debug;
static int mips_revision_corid; static int mips_revision_corid;
int mips_revision_sconid; int mips_revision_sconid;
...@@ -62,74 +36,6 @@ unsigned long _pcictrl_gt64120; ...@@ -62,74 +36,6 @@ unsigned long _pcictrl_gt64120;
/* MIPS System controller register base */ /* MIPS System controller register base */
unsigned long _pcictrl_msc; unsigned long _pcictrl_msc;
char *prom_getenv(char *envname)
{
/*
* Return a pointer to the given environment variable.
* In 64-bit mode: we're using 64-bit pointers, but all pointers
* in the PROM structures are only 32-bit, so we need some
* workarounds, if we are running in 64-bit mode.
*/
int i, index=0;
i = strlen(envname);
while (prom_envp(index)) {
if(strncmp(envname, prom_envp(index), i) == 0) {
return(prom_envp(index+1));
}
index += 2;
}
return NULL;
}
static inline unsigned char str2hexnum(unsigned char c)
{
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
return 0; /* foo */
}
static inline void str2eaddr(unsigned char *ea, unsigned char *str)
{
int i;
for (i = 0; i < 6; i++) {
unsigned char num;
if((*str == '.') || (*str == ':'))
str++;
num = str2hexnum(*str++) << 4;
num |= (str2hexnum(*str++));
ea[i] = num;
}
}
int get_ethernet_addr(char *ethernet_addr)
{
char *ethaddr_str;
ethaddr_str = prom_getenv("ethaddr");
if (!ethaddr_str) {
printk("ethaddr not set in boot prom\n");
return -1;
}
str2eaddr(ethernet_addr, ethaddr_str);
if (init_debug > 1) {
int i;
printk("get_ethernet_addr: ");
for (i=0; i<5; i++)
printk("%02x:", (unsigned char)*(ethernet_addr+i));
printk("%02x\n", *(ethernet_addr+i));
}
return 0;
}
#ifdef CONFIG_SERIAL_8250_CONSOLE #ifdef CONFIG_SERIAL_8250_CONSOLE
static void __init console_config(void) static void __init console_config(void)
{ {
...@@ -138,17 +44,23 @@ static void __init console_config(void) ...@@ -138,17 +44,23 @@ static void __init console_config(void)
char parity = '\0', bits = '\0', flow = '\0'; char parity = '\0', bits = '\0', flow = '\0';
char *s; char *s;
if ((strstr(prom_getcmdline(), "console=")) == NULL) { if ((strstr(fw_getcmdline(), "console=")) == NULL) {
s = prom_getenv("modetty0"); s = fw_getenv("modetty0");
if (s) { if (s) {
while (*s >= '0' && *s <= '9') while (*s >= '0' && *s <= '9')
baud = baud*10 + *s++ - '0'; baud = baud*10 + *s++ - '0';
if (*s == ',') s++; if (*s == ',')
if (*s) parity = *s++; s++;
if (*s == ',') s++; if (*s)
if (*s) bits = *s++; parity = *s++;
if (*s == ',') s++; if (*s == ',')
if (*s == 'h') flow = 'r'; s++;
if (*s)
bits = *s++;
if (*s == ',')
s++;
if (*s == 'h')
flow = 'r';
} }
if (baud == 0) if (baud == 0)
baud = 38400; baud = 38400;
...@@ -158,8 +70,9 @@ static void __init console_config(void) ...@@ -158,8 +70,9 @@ static void __init console_config(void)
bits = '8'; bits = '8';
if (flow == '\0') if (flow == '\0')
flow = 'r'; flow = 'r';
sprintf(console_string, " console=ttyS0,%d%c%c%c", baud, parity, bits, flow); sprintf(console_string, " console=ttyS0,%d%c%c%c", baud,
strcat(prom_getcmdline(), console_string); parity, bits, flow);
strcat(fw_getcmdline(), console_string);
pr_info("Config serial console:%s\n", console_string); pr_info("Config serial console:%s\n", console_string);
} }
} }
...@@ -193,10 +106,6 @@ extern struct plat_smp_ops msmtc_smp_ops; ...@@ -193,10 +106,6 @@ extern struct plat_smp_ops msmtc_smp_ops;
void __init prom_init(void) void __init prom_init(void)
{ {
prom_argc = fw_arg0;
_prom_argv = (int *) fw_arg1;
_prom_envp = (int *) fw_arg2;
mips_display_message("LINUX"); mips_display_message("LINUX");
/* /*
...@@ -306,7 +215,7 @@ void __init prom_init(void) ...@@ -306,7 +215,7 @@ void __init prom_init(void)
case MIPS_REVISION_SCON_SOCIT: case MIPS_REVISION_SCON_SOCIT:
case MIPS_REVISION_SCON_ROCIT: case MIPS_REVISION_SCON_ROCIT:
_pcictrl_msc = (unsigned long)ioremap(MIPS_MSC01_PCI_REG_BASE, 0x2000); _pcictrl_msc = (unsigned long)ioremap(MIPS_MSC01_PCI_REG_BASE, 0x2000);
mips_pci_controller: mips_pci_controller:
mb(); mb();
MSC_READ(MSC01_PCI_CFG, data); MSC_READ(MSC01_PCI_CFG, data);
MSC_WRITE(MSC01_PCI_CFG, data & ~MSC01_PCI_CFG_EN_BIT); MSC_WRITE(MSC01_PCI_CFG, data & ~MSC01_PCI_CFG_EN_BIT);
...@@ -348,13 +257,13 @@ void __init prom_init(void) ...@@ -348,13 +257,13 @@ void __init prom_init(void)
default: default:
/* Unknown system controller */ /* Unknown system controller */
mips_display_message("SC Error"); mips_display_message("SC Error");
while (1); /* We die here... */ while (1); /* We die here... */
} }
board_nmi_handler_setup = mips_nmi_setup; board_nmi_handler_setup = mips_nmi_setup;
board_ejtag_handler_setup = mips_ejtag_setup; board_ejtag_handler_setup = mips_ejtag_setup;
prom_init_cmdline(); fw_init_cmdline();
prom_meminit(); fw_meminit();
#ifdef CONFIG_SERIAL_8250_CONSOLE #ifdef CONFIG_SERIAL_8250_CONSOLE
console_config(); console_config();
#endif #endif
......
...@@ -47,7 +47,6 @@ ...@@ -47,7 +47,6 @@
#include <asm/setup.h> #include <asm/setup.h>
int gcmp_present = -1; int gcmp_present = -1;
int gic_present;
static unsigned long _msc01_biu_base; static unsigned long _msc01_biu_base;
static unsigned long _gcmp_base; static unsigned long _gcmp_base;
static unsigned int ipi_map[NR_CPUS]; static unsigned int ipi_map[NR_CPUS];
...@@ -134,6 +133,9 @@ static void malta_ipi_irqdispatch(void) ...@@ -134,6 +133,9 @@ static void malta_ipi_irqdispatch(void)
{ {
int irq; int irq;
if (gic_compare_int())
do_IRQ(MIPS_GIC_IRQ_BASE);
irq = gic_get_int(); irq = gic_get_int();
if (irq < 0) if (irq < 0)
return; /* interrupt has already been cleared */ return; /* interrupt has already been cleared */
......
/* /*
* Carsten Langgaard, carstenl@mips.com * This file is subject to the terms and conditions of the GNU General Public
* Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. * License. See the file "COPYING" in the main directory of this archive
* * for more details.
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
* *
* PROM library functions for acquiring/using memory descriptors given to * PROM library functions for acquiring/using memory descriptors given to
* us from the YAMON. * us from the YAMON.
*
* Copyright (C) 1999,2000,2012 MIPS Technologies, Inc.
* All rights reserved.
* Authors: Carsten Langgaard <carstenl@mips.com>
* Steven J. Hill <sjhill@mips.com>
*/ */
#include <linux/init.h> #include <linux/init.h>
#include <linux/mm.h>
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/pfn.h>
#include <linux/string.h> #include <linux/string.h>
#include <asm/bootinfo.h> #include <asm/bootinfo.h>
#include <asm/page.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/fw/fw.h>
#include <asm/mips-boards/prom.h> static fw_memblock_t mdesc[FW_MAX_MEMBLOCKS];
/*#define DEBUG*/
enum yamon_memtypes {
yamon_dontuse,
yamon_prom,
yamon_free,
};
static struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS];
#ifdef DEBUG
static char *mtypes[3] = {
"Dont use memory",
"YAMON PROM memory",
"Free memory",
};
#endif
/* determined physical memory size, not overridden by command line args */ /* determined physical memory size, not overridden by command line args */
unsigned long physical_memsize = 0L; unsigned long physical_memsize = 0L;
static struct prom_pmemblock * __init prom_getmdesc(void) fw_memblock_t * __init fw_getmdesc(void)
{ {
char *memsize_str; char *memsize_str, *ptr;
unsigned int memsize; unsigned int memsize;
char *ptr;
static char cmdline[COMMAND_LINE_SIZE] __initdata; static char cmdline[COMMAND_LINE_SIZE] __initdata;
long val;
int tmp;
/* otherwise look in the environment */ /* otherwise look in the environment */
memsize_str = prom_getenv("memsize"); memsize_str = fw_getenv("memsize");
if (!memsize_str) { if (!memsize_str) {
printk(KERN_WARNING pr_warn("memsize not set in YAMON, set to default (32Mb)\n");
"memsize not set in boot prom, set to default (32Mb)\n");
physical_memsize = 0x02000000; physical_memsize = 0x02000000;
} else { } else {
#ifdef DEBUG tmp = kstrtol(memsize_str, 0, &val);
pr_debug("prom_memsize = %s\n", memsize_str); physical_memsize = (unsigned long)val;
#endif
physical_memsize = simple_strtol(memsize_str, NULL, 0);
} }
#ifdef CONFIG_CPU_BIG_ENDIAN #ifdef CONFIG_CPU_BIG_ENDIAN
...@@ -90,11 +62,11 @@ static struct prom_pmemblock * __init prom_getmdesc(void) ...@@ -90,11 +62,11 @@ static struct prom_pmemblock * __init prom_getmdesc(void)
memset(mdesc, 0, sizeof(mdesc)); memset(mdesc, 0, sizeof(mdesc));
mdesc[0].type = yamon_dontuse; mdesc[0].type = fw_dontuse;
mdesc[0].base = 0x00000000; mdesc[0].base = 0x00000000;
mdesc[0].size = 0x00001000; mdesc[0].size = 0x00001000;
mdesc[1].type = yamon_prom; mdesc[1].type = fw_code;
mdesc[1].base = 0x00001000; mdesc[1].base = 0x00001000;
mdesc[1].size = 0x000ef000; mdesc[1].size = 0x000ef000;
...@@ -105,55 +77,45 @@ static struct prom_pmemblock * __init prom_getmdesc(void) ...@@ -105,55 +77,45 @@ static struct prom_pmemblock * __init prom_getmdesc(void)
* This mean that this area can't be used as DMA memory for PCI * This mean that this area can't be used as DMA memory for PCI
* devices. * devices.
*/ */
mdesc[2].type = yamon_dontuse; mdesc[2].type = fw_dontuse;
mdesc[2].base = 0x000f0000; mdesc[2].base = 0x000f0000;
mdesc[2].size = 0x00010000; mdesc[2].size = 0x00010000;
mdesc[3].type = yamon_dontuse; mdesc[3].type = fw_dontuse;
mdesc[3].base = 0x00100000; mdesc[3].base = 0x00100000;
mdesc[3].size = CPHYSADDR(PFN_ALIGN((unsigned long)&_end)) - mdesc[3].base; mdesc[3].size = CPHYSADDR(PFN_ALIGN((unsigned long)&_end)) -
mdesc[3].base;
mdesc[4].type = yamon_free; mdesc[4].type = fw_free;
mdesc[4].base = CPHYSADDR(PFN_ALIGN(&_end)); mdesc[4].base = CPHYSADDR(PFN_ALIGN(&_end));
mdesc[4].size = memsize - mdesc[4].base; mdesc[4].size = memsize - mdesc[4].base;
return &mdesc[0]; return &mdesc[0];
} }
static int __init prom_memtype_classify(unsigned int type) static int __init fw_memtype_classify(unsigned int type)
{ {
switch (type) { switch (type) {
case yamon_free: case fw_free:
return BOOT_MEM_RAM; return BOOT_MEM_RAM;
case yamon_prom: case fw_code:
return BOOT_MEM_ROM_DATA; return BOOT_MEM_ROM_DATA;
default: default:
return BOOT_MEM_RESERVED; return BOOT_MEM_RESERVED;
} }
} }
void __init prom_meminit(void) void __init fw_meminit(void)
{ {
struct prom_pmemblock *p; fw_memblock_t *p;
#ifdef DEBUG p = fw_getmdesc();
pr_debug("YAMON MEMORY DESCRIPTOR dump:\n");
p = prom_getmdesc();
while (p->size) {
int i = 0;
pr_debug("[%d,%p]: base<%08lx> size<%08lx> type<%s>\n",
i, p, p->base, p->size, mtypes[p->type]);
p++;
i++;
}
#endif
p = prom_getmdesc();
while (p->size) { while (p->size) {
long type; long type;
unsigned long base, size; unsigned long base, size;
type = prom_memtype_classify(p->type); type = fw_memtype_classify(p->type);
base = p->base; base = p->base;
size = p->size; size = p->size;
...@@ -172,7 +134,7 @@ void __init prom_free_prom_memory(void) ...@@ -172,7 +134,7 @@ void __init prom_free_prom_memory(void)
continue; continue;
addr = boot_mem_map.map[i].addr; addr = boot_mem_map.map[i].addr;
free_init_pages("prom memory", free_init_pages("YAMON memory",
addr, addr + boot_mem_map.map[i].size); addr, addr + boot_mem_map.map[i].size);
} }
} }
...@@ -25,13 +25,13 @@ ...@@ -25,13 +25,13 @@
#include <linux/screen_info.h> #include <linux/screen_info.h>
#include <linux/time.h> #include <linux/time.h>
#include <asm/bootinfo.h> #include <asm/fw/fw.h>
#include <asm/mips-boards/generic.h> #include <asm/mips-boards/generic.h>
#include <asm/mips-boards/prom.h>
#include <asm/mips-boards/malta.h> #include <asm/mips-boards/malta.h>
#include <asm/mips-boards/maltaint.h> #include <asm/mips-boards/maltaint.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/traps.h> #include <asm/traps.h>
#include <asm/gcmpregs.h>
#ifdef CONFIG_VT #ifdef CONFIG_VT
#include <linux/console.h> #include <linux/console.h>
#endif #endif
...@@ -105,6 +105,66 @@ static void __init fd_activate(void) ...@@ -105,6 +105,66 @@ static void __init fd_activate(void)
} }
#endif #endif
static int __init plat_enable_iocoherency(void)
{
int supported = 0;
if (mips_revision_sconid == MIPS_REVISION_SCON_BONITO) {
if (BONITO_PCICACHECTRL & BONITO_PCICACHECTRL_CPUCOH_PRES) {
BONITO_PCICACHECTRL |= BONITO_PCICACHECTRL_CPUCOH_EN;
pr_info("Enabled Bonito CPU coherency\n");
supported = 1;
}
if (strstr(fw_getcmdline(), "iobcuncached")) {
BONITO_PCICACHECTRL &= ~BONITO_PCICACHECTRL_IOBCCOH_EN;
BONITO_PCIMEMBASECFG = BONITO_PCIMEMBASECFG &
~(BONITO_PCIMEMBASECFG_MEMBASE0_CACHED |
BONITO_PCIMEMBASECFG_MEMBASE1_CACHED);
pr_info("Disabled Bonito IOBC coherency\n");
} else {
BONITO_PCICACHECTRL |= BONITO_PCICACHECTRL_IOBCCOH_EN;
BONITO_PCIMEMBASECFG |=
(BONITO_PCIMEMBASECFG_MEMBASE0_CACHED |
BONITO_PCIMEMBASECFG_MEMBASE1_CACHED);
pr_info("Enabled Bonito IOBC coherency\n");
}
} else if (gcmp_niocu() != 0) {
/* Nothing special needs to be done to enable coherency */
pr_info("CMP IOCU detected\n");
if ((*(unsigned int *)0xbf403000 & 0x81) != 0x81) {
pr_crit("IOCU OPERATION DISABLED BY SWITCH - DEFAULTING TO SW IO COHERENCY\n");
return 0;
}
supported = 1;
}
hw_coherentio = supported;
return supported;
}
static void __init plat_setup_iocoherency(void)
{
#ifdef CONFIG_DMA_NONCOHERENT
/*
* Kernel has been configured with software coherency
* but we might choose to turn it off and use hardware
* coherency instead.
*/
if (plat_enable_iocoherency()) {
if (coherentio == 0)
pr_info("Hardware DMA cache coherency disabled\n");
else
pr_info("Hardware DMA cache coherency enabled\n");
} else {
if (coherentio == 1)
pr_info("Hardware DMA cache coherency unsupported, but enabled from command line!\n");
else
pr_info("Software DMA cache coherency enabled\n");
}
#else
if (!plat_enable_iocoherency())
panic("Hardware DMA cache coherency not supported!");
#endif
}
#ifdef CONFIG_BLK_DEV_IDE #ifdef CONFIG_BLK_DEV_IDE
static void __init pci_clock_check(void) static void __init pci_clock_check(void)
{ {
...@@ -115,16 +175,15 @@ static void __init pci_clock_check(void) ...@@ -115,16 +175,15 @@ static void __init pci_clock_check(void)
33, 20, 25, 30, 12, 16, 37, 10 33, 20, 25, 30, 12, 16, 37, 10
}; };
int pciclock = pciclocks[jmpr]; int pciclock = pciclocks[jmpr];
char *argptr = prom_getcmdline(); char *argptr = fw_getcmdline();
if (pciclock != 33 && !strstr(argptr, "idebus=")) { if (pciclock != 33 && !strstr(argptr, "idebus=")) {
printk(KERN_WARNING "WARNING: PCI clock is %dMHz, " pr_warn("WARNING: PCI clock is %dMHz, setting idebus\n",
"setting idebus\n", pciclock); pciclock);
argptr += strlen(argptr); argptr += strlen(argptr);
sprintf(argptr, " idebus=%d", pciclock); sprintf(argptr, " idebus=%d", pciclock);
if (pciclock < 20 || pciclock > 66) if (pciclock < 20 || pciclock > 66)
printk(KERN_WARNING "WARNING: IDE timing " pr_warn("WARNING: IDE timing calculations will be incorrect\n");
"calculations will be incorrect\n");
} }
} }
#endif #endif
...@@ -153,31 +212,31 @@ static void __init bonito_quirks_setup(void) ...@@ -153,31 +212,31 @@ static void __init bonito_quirks_setup(void)
{ {
char *argptr; char *argptr;
argptr = prom_getcmdline(); argptr = fw_getcmdline();
if (strstr(argptr, "debug")) { if (strstr(argptr, "debug")) {
BONITO_BONGENCFG |= BONITO_BONGENCFG_DEBUGMODE; BONITO_BONGENCFG |= BONITO_BONGENCFG_DEBUGMODE;
printk(KERN_INFO "Enabled Bonito debug mode\n"); pr_info("Enabled Bonito debug mode\n");
} else } else
BONITO_BONGENCFG &= ~BONITO_BONGENCFG_DEBUGMODE; BONITO_BONGENCFG &= ~BONITO_BONGENCFG_DEBUGMODE;
#ifdef CONFIG_DMA_COHERENT #ifdef CONFIG_DMA_COHERENT
if (BONITO_PCICACHECTRL & BONITO_PCICACHECTRL_CPUCOH_PRES) { if (BONITO_PCICACHECTRL & BONITO_PCICACHECTRL_CPUCOH_PRES) {
BONITO_PCICACHECTRL |= BONITO_PCICACHECTRL_CPUCOH_EN; BONITO_PCICACHECTRL |= BONITO_PCICACHECTRL_CPUCOH_EN;
printk(KERN_INFO "Enabled Bonito CPU coherency\n"); pr_info("Enabled Bonito CPU coherency\n");
argptr = prom_getcmdline(); argptr = fw_getcmdline();
if (strstr(argptr, "iobcuncached")) { if (strstr(argptr, "iobcuncached")) {
BONITO_PCICACHECTRL &= ~BONITO_PCICACHECTRL_IOBCCOH_EN; BONITO_PCICACHECTRL &= ~BONITO_PCICACHECTRL_IOBCCOH_EN;
BONITO_PCIMEMBASECFG = BONITO_PCIMEMBASECFG & BONITO_PCIMEMBASECFG = BONITO_PCIMEMBASECFG &
~(BONITO_PCIMEMBASECFG_MEMBASE0_CACHED | ~(BONITO_PCIMEMBASECFG_MEMBASE0_CACHED |
BONITO_PCIMEMBASECFG_MEMBASE1_CACHED); BONITO_PCIMEMBASECFG_MEMBASE1_CACHED);
printk(KERN_INFO "Disabled Bonito IOBC coherency\n"); pr_info("Disabled Bonito IOBC coherency\n");
} else { } else {
BONITO_PCICACHECTRL |= BONITO_PCICACHECTRL_IOBCCOH_EN; BONITO_PCICACHECTRL |= BONITO_PCICACHECTRL_IOBCCOH_EN;
BONITO_PCIMEMBASECFG |= BONITO_PCIMEMBASECFG |=
(BONITO_PCIMEMBASECFG_MEMBASE0_CACHED | (BONITO_PCIMEMBASECFG_MEMBASE0_CACHED |
BONITO_PCIMEMBASECFG_MEMBASE1_CACHED); BONITO_PCIMEMBASECFG_MEMBASE1_CACHED);
printk(KERN_INFO "Enabled Bonito IOBC coherency\n"); pr_info("Enabled Bonito IOBC coherency\n");
} }
} else } else
panic("Hardware DMA cache coherency not supported"); panic("Hardware DMA cache coherency not supported");
...@@ -207,6 +266,8 @@ void __init plat_mem_setup(void) ...@@ -207,6 +266,8 @@ void __init plat_mem_setup(void)
if (mips_revision_sconid == MIPS_REVISION_SCON_BONITO) if (mips_revision_sconid == MIPS_REVISION_SCON_BONITO)
bonito_quirks_setup(); bonito_quirks_setup();
plat_setup_iocoherency();
#ifdef CONFIG_BLK_DEV_IDE #ifdef CONFIG_BLK_DEV_IDE
pci_clock_check(); pci_clock_check();
#endif #endif
......
...@@ -39,12 +39,9 @@ ...@@ -39,12 +39,9 @@
#include <asm/gic.h> #include <asm/gic.h>
#include <asm/mips-boards/generic.h> #include <asm/mips-boards/generic.h>
#include <asm/mips-boards/prom.h>
#include <asm/mips-boards/maltaint.h> #include <asm/mips-boards/maltaint.h>
unsigned long cpu_khz; unsigned long cpu_khz;
int gic_frequency;
static int mips_cpu_timer_irq; static int mips_cpu_timer_irq;
static int mips_cpu_perf_irq; static int mips_cpu_perf_irq;
...@@ -74,7 +71,9 @@ static void __init estimate_frequencies(void) ...@@ -74,7 +71,9 @@ static void __init estimate_frequencies(void)
{ {
unsigned long flags; unsigned long flags;
unsigned int count, start; unsigned int count, start;
#ifdef CONFIG_IRQ_GIC
unsigned int giccount = 0, gicstart = 0; unsigned int giccount = 0, gicstart = 0;
#endif
#if defined (CONFIG_KVM_GUEST) && defined (CONFIG_KVM_HOST_FREQ) #if defined (CONFIG_KVM_GUEST) && defined (CONFIG_KVM_HOST_FREQ)
unsigned int prid = read_c0_prid() & 0xffff00; unsigned int prid = read_c0_prid() & 0xffff00;
...@@ -99,26 +98,32 @@ static void __init estimate_frequencies(void) ...@@ -99,26 +98,32 @@ static void __init estimate_frequencies(void)
/* Initialize counters. */ /* Initialize counters. */
start = read_c0_count(); start = read_c0_count();
#ifdef CONFIG_IRQ_GIC
if (gic_present) if (gic_present)
GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), gicstart); GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), gicstart);
#endif
/* Read counter exactly on falling edge of update flag. */ /* Read counter exactly on falling edge of update flag. */
while (CMOS_READ(RTC_REG_A) & RTC_UIP); while (CMOS_READ(RTC_REG_A) & RTC_UIP);
while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
count = read_c0_count(); count = read_c0_count();
#ifdef CONFIG_IRQ_GIC
if (gic_present) if (gic_present)
GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), giccount); GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), giccount);
#endif
local_irq_restore(flags); local_irq_restore(flags);
count -= start; count -= start;
if (gic_present)
giccount -= gicstart;
mips_hpt_frequency = count; mips_hpt_frequency = count;
if (gic_present)
#ifdef CONFIG_IRQ_GIC
if (gic_present) {
giccount -= gicstart;
gic_frequency = giccount; gic_frequency = giccount;
}
#endif
} }
void read_persistent_clock(struct timespec *ts) void read_persistent_clock(struct timespec *ts)
...@@ -174,24 +179,27 @@ void __init plat_time_init(void) ...@@ -174,24 +179,27 @@ void __init plat_time_init(void)
(prid != (PRID_COMP_MIPS | PRID_IMP_25KF))) (prid != (PRID_COMP_MIPS | PRID_IMP_25KF)))
freq *= 2; freq *= 2;
freq = freqround(freq, 5000); freq = freqround(freq, 5000);
pr_debug("CPU frequency %d.%02d MHz\n", freq/1000000, printk("CPU frequency %d.%02d MHz\n", freq/1000000,
(freq%1000000)*100/1000000); (freq%1000000)*100/1000000);
cpu_khz = freq / 1000; cpu_khz = freq / 1000;
if (gic_present) { mips_scroll_message();
freq = freqround(gic_frequency, 5000);
pr_debug("GIC frequency %d.%02d MHz\n", freq/1000000,
(freq%1000000)*100/1000000);
gic_clocksource_init(gic_frequency);
} else
init_r4k_clocksource();
#ifdef CONFIG_I8253 #ifdef CONFIG_I8253
/* Only Malta has a PIT. */ /* Only Malta has a PIT. */
setup_pit_timer(); setup_pit_timer();
#endif #endif
mips_scroll_message(); #ifdef CONFIG_IRQ_GIC
if (gic_present) {
freq = freqround(gic_frequency, 5000);
printk("GIC frequency %d.%02d MHz\n", freq/1000000,
(freq%1000000)*100/1000000);
#ifdef CONFIG_CSRC_GIC
gic_clocksource_init(gic_frequency);
#endif
}
#endif
plat_perf_setup(); plat_perf_setup();
} }
...@@ -8,10 +8,10 @@ ...@@ -8,10 +8,10 @@
# Copyright (C) 2012 MIPS Technoligies, Inc. All rights reserved. # Copyright (C) 2012 MIPS Technoligies, Inc. All rights reserved.
# Steven J. Hill <sjhill@mips.com> # Steven J. Hill <sjhill@mips.com>
# #
obj-y := sead3-lcd.o sead3-cmdline.o \ obj-y := sead3-lcd.o sead3-display.o sead3-init.o \
sead3-display.o sead3-init.o sead3-int.o \ sead3-int.o sead3-mtd.o sead3-net.o \
sead3-mtd.o sead3-net.o sead3-platform.o \ sead3-platform.o sead3-reset.o \
sead3-reset.o sead3-setup.o sead3-time.o sead3-setup.o sead3-time.o
obj-y += sead3-i2c-dev.o sead3-i2c.o \ obj-y += sead3-i2c-dev.o sead3-i2c.o \
sead3-pic32-i2c-drv.o sead3-pic32-bus.o \ sead3-pic32-i2c-drv.o sead3-pic32-bus.o \
......
...@@ -34,33 +34,15 @@ static void sead3_fled_set(struct led_classdev *led_cdev, ...@@ -34,33 +34,15 @@ static void sead3_fled_set(struct led_classdev *led_cdev,
static struct led_classdev sead3_pled = { static struct led_classdev sead3_pled = {
.name = "sead3::pled", .name = "sead3::pled",
.brightness_set = sead3_pled_set, .brightness_set = sead3_pled_set,
.flags = LED_CORE_SUSPENDRESUME,
}; };
static struct led_classdev sead3_fled = { static struct led_classdev sead3_fled = {
.name = "sead3::fled", .name = "sead3::fled",
.brightness_set = sead3_fled_set, .brightness_set = sead3_fled_set,
.flags = LED_CORE_SUSPENDRESUME,
}; };
#ifdef CONFIG_PM
static int sead3_led_suspend(struct platform_device *dev,
pm_message_t state)
{
led_classdev_suspend(&sead3_pled);
led_classdev_suspend(&sead3_fled);
return 0;
}
static int sead3_led_resume(struct platform_device *dev)
{
led_classdev_resume(&sead3_pled);
led_classdev_resume(&sead3_fled);
return 0;
}
#else
#define sead3_led_suspend NULL
#define sead3_led_resume NULL
#endif
static int sead3_led_probe(struct platform_device *pdev) static int sead3_led_probe(struct platform_device *pdev)
{ {
int ret; int ret;
...@@ -86,8 +68,6 @@ static int sead3_led_remove(struct platform_device *pdev) ...@@ -86,8 +68,6 @@ static int sead3_led_remove(struct platform_device *pdev)
static struct platform_driver sead3_led_driver = { static struct platform_driver sead3_led_driver = {
.probe = sead3_led_probe, .probe = sead3_led_probe,
.remove = sead3_led_remove, .remove = sead3_led_remove,
.suspend = sead3_led_suspend,
.resume = sead3_led_resume,
.driver = { .driver = {
.name = DRVNAME, .name = DRVNAME,
.owner = THIS_MODULE, .owner = THIS_MODULE,
......
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
*/
#include <linux/init.h>
#include <linux/string.h>
#include <asm/bootinfo.h>
extern int prom_argc;
extern int *_prom_argv;
/*
* YAMON (32-bit PROM) pass arguments and environment as 32-bit pointer.
* This macro take care of sign extension.
*/
#define prom_argv(index) ((char *)(long)_prom_argv[(index)])
char * __init prom_getcmdline(void)
{
return &(arcs_cmdline[0]);
}
void __init prom_init_cmdline(void)
{
char *cp;
int actr;
actr = 1; /* Always ignore argv[0] */
cp = &(arcs_cmdline[0]);
while (actr < prom_argc) {
strcpy(cp, prom_argv(actr));
cp += strlen(prom_argv(actr));
*cp++ = ' ';
actr++;
}
if (cp != &(arcs_cmdline[0])) {
/* get rid of trailing space */
--cp;
*cp = '\0';
}
}
...@@ -26,7 +26,7 @@ static inline void serial_out(int offset, int value, unsigned int base_addr) ...@@ -26,7 +26,7 @@ static inline void serial_out(int offset, int value, unsigned int base_addr)
__raw_writel(value, PORT(base_addr, offset)); __raw_writel(value, PORT(base_addr, offset));
} }
void __init prom_init_early_console(char port) void __init fw_init_early_console(char port)
{ {
console_port = port; console_port = port;
} }
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/io.h> #include <linux/io.h>
#include <asm/mips-boards/generic.h> #include <asm/mips-boards/generic.h>
#include <asm/mips-boards/prom.h>
static unsigned int display_count; static unsigned int display_count;
static unsigned int max_display_count; static unsigned int max_display_count;
......
...@@ -12,38 +12,51 @@ ...@@ -12,38 +12,51 @@
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/traps.h> #include <asm/traps.h>
#include <asm/mips-boards/generic.h> #include <asm/mips-boards/generic.h>
#include <asm/mips-boards/prom.h> #include <asm/fw/fw.h>
extern void prom_init_early_console(char port);
extern char except_vec_nmi; extern char except_vec_nmi;
extern char except_vec_ejtag_debug; extern char except_vec_ejtag_debug;
int prom_argc; #ifdef CONFIG_SERIAL_8250_CONSOLE
int *_prom_argv, *_prom_envp; static void __init console_config(void)
#define prom_envp(index) ((char *)(long)_prom_envp[(index)])
char *prom_getenv(char *envname)
{ {
/* char console_string[40];
* Return a pointer to the given environment variable. int baud = 0;
* In 64-bit mode: we're using 64-bit pointers, but all pointers char parity = '\0', bits = '\0', flow = '\0';
* in the PROM structures are only 32-bit, so we need some char *s;
* workarounds, if we are running in 64-bit mode.
*/ if ((strstr(fw_getcmdline(), "console=")) == NULL) {
int i, index = 0; s = fw_getenv("modetty0");
if (s) {
i = strlen(envname); while (*s >= '0' && *s <= '9')
baud = baud*10 + *s++ - '0';
while (prom_envp(index)) { if (*s == ',')
if (strncmp(envname, prom_envp(index), i) == 0) s++;
return prom_envp(index+1); if (*s)
index += 2; parity = *s++;
if (*s == ',')
s++;
if (*s)
bits = *s++;
if (*s == ',')
s++;
if (*s == 'h')
flow = 'r';
}
if (baud == 0)
baud = 38400;
if (parity != 'n' && parity != 'o' && parity != 'e')
parity = 'n';
if (bits != '7' && bits != '8')
bits = '8';
if (flow == '\0')
flow = 'r';
sprintf(console_string, " console=ttyS0,%d%c%c%c", baud,
parity, bits, flow);
strcat(fw_getcmdline(), console_string);
} }
return NULL;
} }
#endif
static void __init mips_nmi_setup(void) static void __init mips_nmi_setup(void)
{ {
...@@ -52,7 +65,41 @@ static void __init mips_nmi_setup(void) ...@@ -52,7 +65,41 @@ static void __init mips_nmi_setup(void)
base = cpu_has_veic ? base = cpu_has_veic ?
(void *)(CAC_BASE + 0xa80) : (void *)(CAC_BASE + 0xa80) :
(void *)(CAC_BASE + 0x380); (void *)(CAC_BASE + 0x380);
#ifdef CONFIG_CPU_MICROMIPS
/*
* Decrement the exception vector address by one for microMIPS.
*/
memcpy(base, (&except_vec_nmi - 1), 0x80);
/*
* This is a hack. We do not know if the boot loader was built with
* microMIPS instructions or not. If it was not, the NMI exception
* code at 0x80000a80 will be taken in MIPS32 mode. The hand coded
* assembly below forces us into microMIPS mode if we are a pure
* microMIPS kernel. The assembly instructions are:
*
* 3C1A8000 lui k0,0x8000
* 375A0381 ori k0,k0,0x381
* 03400008 jr k0
* 00000000 nop
*
* The mode switch occurs by jumping to the unaligned exception
* vector address at 0x80000381 which would have been 0x80000380
* in MIPS32 mode. The jump to the unaligned address transitions
* us into microMIPS mode.
*/
if (!cpu_has_veic) {
void *base2 = (void *)(CAC_BASE + 0xa80);
*((unsigned int *)base2) = 0x3c1a8000;
*((unsigned int *)base2 + 1) = 0x375a0381;
*((unsigned int *)base2 + 2) = 0x03400008;
*((unsigned int *)base2 + 3) = 0x00000000;
flush_icache_range((unsigned long)base2,
(unsigned long)base2 + 0x10);
}
#else
memcpy(base, &except_vec_nmi, 0x80); memcpy(base, &except_vec_nmi, 0x80);
#endif
flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); flush_icache_range((unsigned long)base, (unsigned long)base + 0x80);
} }
...@@ -63,29 +110,40 @@ static void __init mips_ejtag_setup(void) ...@@ -63,29 +110,40 @@ static void __init mips_ejtag_setup(void)
base = cpu_has_veic ? base = cpu_has_veic ?
(void *)(CAC_BASE + 0xa00) : (void *)(CAC_BASE + 0xa00) :
(void *)(CAC_BASE + 0x300); (void *)(CAC_BASE + 0x300);
#ifdef CONFIG_CPU_MICROMIPS
/* Deja vu... */
memcpy(base, (&except_vec_ejtag_debug - 1), 0x80);
if (!cpu_has_veic) {
void *base2 = (void *)(CAC_BASE + 0xa00);
*((unsigned int *)base2) = 0x3c1a8000;
*((unsigned int *)base2 + 1) = 0x375a0301;
*((unsigned int *)base2 + 2) = 0x03400008;
*((unsigned int *)base2 + 3) = 0x00000000;
flush_icache_range((unsigned long)base2,
(unsigned long)base2 + 0x10);
}
#else
memcpy(base, &except_vec_ejtag_debug, 0x80); memcpy(base, &except_vec_ejtag_debug, 0x80);
#endif
flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); flush_icache_range((unsigned long)base, (unsigned long)base + 0x80);
} }
void __init prom_init(void) void __init prom_init(void)
{ {
prom_argc = fw_arg0;
_prom_argv = (int *) fw_arg1;
_prom_envp = (int *) fw_arg2;
board_nmi_handler_setup = mips_nmi_setup; board_nmi_handler_setup = mips_nmi_setup;
board_ejtag_handler_setup = mips_ejtag_setup; board_ejtag_handler_setup = mips_ejtag_setup;
prom_init_cmdline(); fw_init_cmdline();
#ifdef CONFIG_EARLY_PRINTK #ifdef CONFIG_EARLY_PRINTK
if ((strstr(prom_getcmdline(), "console=ttyS0")) != NULL) if ((strstr(fw_getcmdline(), "console=ttyS0")) != NULL)
prom_init_early_console(0); fw_init_early_console(0);
else if ((strstr(prom_getcmdline(), "console=ttyS1")) != NULL) else if ((strstr(fw_getcmdline(), "console=ttyS1")) != NULL)
prom_init_early_console(1); fw_init_early_console(1);
#endif #endif
#ifdef CONFIG_SERIAL_8250_CONSOLE #ifdef CONFIG_SERIAL_8250_CONSOLE
if ((strstr(prom_getcmdline(), "console=")) == NULL) if ((strstr(fw_getcmdline(), "console=")) == NULL)
strcat(prom_getcmdline(), " console=ttyS0,38400n8r"); strcat(fw_getcmdline(), " console=ttyS0,38400n8r");
console_config();
#endif #endif
} }
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#define SEAD_CONFIG_BASE 0x1b100110 #define SEAD_CONFIG_BASE 0x1b100110
#define SEAD_CONFIG_SIZE 4 #define SEAD_CONFIG_SIZE 4
int gic_present;
static unsigned long sead3_config_reg; static unsigned long sead3_config_reg;
/* /*
......
...@@ -11,10 +11,6 @@ ...@@ -11,10 +11,6 @@
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <asm/mips-boards/generic.h> #include <asm/mips-boards/generic.h>
#include <asm/prom.h>
int coherentio; /* 0 => no DMA cache coherency (may be set by user) */
int hw_coherentio; /* 0 => no HW DMA cache coherency (reflects real HW) */
const char *get_system_type(void) const char *get_system_type(void)
{ {
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include <asm/time.h> #include <asm/time.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/mips-boards/generic.h> #include <asm/mips-boards/generic.h>
#include <asm/mips-boards/prom.h>
unsigned long cpu_khz; unsigned long cpu_khz;
......
...@@ -29,10 +29,11 @@ ...@@ -29,10 +29,11 @@
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/traps.h> #include <asm/traps.h>
#include <asm/mips-boards/prom.h>
#include <asm/mips-boards/generic.h> #include <asm/mips-boards/generic.h>
#include <asm/mach-powertv/asic.h> #include <asm/mach-powertv/asic.h>
#include "init.h"
static int *_prom_envp; static int *_prom_envp;
unsigned long _prom_memsize; unsigned long _prom_memsize;
......
...@@ -23,4 +23,6 @@ ...@@ -23,4 +23,6 @@
#ifndef _POWERTV_INIT_H #ifndef _POWERTV_INIT_H
#define _POWERTV_INIT_H #define _POWERTV_INIT_H
extern unsigned long _prom_memsize; extern unsigned long _prom_memsize;
extern void prom_meminit(void);
extern char *prom_getenv(char *name);
#endif #endif
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
#include <asm/page.h> #include <asm/page.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/mips-boards/prom.h>
#include <asm/mach-powertv/asic.h> #include <asm/mach-powertv/asic.h>
#include <asm/mach-powertv/ioremap.h> #include <asm/mach-powertv/ioremap.h>
......
...@@ -31,7 +31,6 @@ ...@@ -31,7 +31,6 @@
#include <asm/bootinfo.h> #include <asm/bootinfo.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/mips-boards/generic.h> #include <asm/mips-boards/generic.h>
#include <asm/mips-boards/prom.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/asm.h> #include <asm/asm.h>
#include <asm/traps.h> #include <asm/traps.h>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment