diff options
Diffstat (limited to 'arch/sparc64')
-rw-r--r-- | arch/sparc64/Kconfig | 3 | ||||
-rw-r--r-- | arch/sparc64/defconfig | 155 | ||||
-rw-r--r-- | arch/sparc64/kernel/ds.c | 289 | ||||
-rw-r--r-- | arch/sparc64/kernel/hvtramp.S | 3 | ||||
-rw-r--r-- | arch/sparc64/kernel/mdesc.c | 96 | ||||
-rw-r--r-- | arch/sparc64/kernel/setup.c | 4 | ||||
-rw-r--r-- | arch/sparc64/kernel/signal.c | 15 | ||||
-rw-r--r-- | arch/sparc64/kernel/traps.c | 1 | ||||
-rw-r--r-- | arch/sparc64/kernel/vio.c | 94 | ||||
-rw-r--r-- | arch/sparc64/kernel/viohs.c | 30 | ||||
-rw-r--r-- | arch/sparc64/kernel/vmlinux.lds.S | 6 | ||||
-rw-r--r-- | arch/sparc64/mm/fault.c | 24 | ||||
-rw-r--r-- | arch/sparc64/solaris/socksys.c | 3 |
13 files changed, 388 insertions, 335 deletions
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index b84b6af1241..df6ee71894d 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -62,6 +62,9 @@ config AUDIT_ARCH bool default y +config ARCH_NO_VIRT_TO_BUS + def_bool y + choice prompt "Kernel page size" default SPARC64_PAGE_SIZE_8KB diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 65840a62bb9..45ebf91a280 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.22-rc1 -# Mon May 14 04:17:48 2007 +# Linux kernel version: 2.6.22 +# Tue Jul 17 01:19:52 2007 # CONFIG_SPARC=y CONFIG_SPARC64=y @@ -42,12 +42,11 @@ CONFIG_LOCALVERSION="" # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SWAP=y CONFIG_SYSVIPC=y -# CONFIG_IPC_NS is not set CONFIG_SYSVIPC_SYSCTL=y CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_TASKSTATS is not set -# CONFIG_UTS_NS is not set +# CONFIG_USER_NS is not set # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set CONFIG_LOG_BUF_SHIFT=18 @@ -82,22 +81,15 @@ CONFIG_SLUB=y CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 - -# -# Loadable module support -# CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SRCVERSION_ALL=y CONFIG_KMOD=y - -# -# Block layer -# CONFIG_BLOCK=y CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_BLK_DEV_BSG=y # # IO Schedulers @@ -156,12 +148,15 @@ CONFIG_SPLIT_PTLOCK_CPUS=4 CONFIG_RESOURCES_64BIT=y CONFIG_ZONE_DMA_FLAG=0 CONFIG_NR_QUICK=1 +CONFIG_VIRT_TO_BUS=y CONFIG_SBUS=y CONFIG_SBUSCHAR=y CONFIG_SUN_AUXIO=y CONFIG_SUN_IO=y +# CONFIG_SUN_LDOMS is not set CONFIG_PCI=y CONFIG_PCI_DOMAINS=y +CONFIG_PCI_SYSCALL=y CONFIG_ARCH_SUPPORTS_MSI=y CONFIG_PCI_MSI=y # CONFIG_PCI_DEBUG is not set @@ -246,10 +241,6 @@ CONFIG_IPV6_TUNNEL=m # CONFIG_IPV6_MULTIPLE_TABLES is not set # CONFIG_NETWORK_SECMARK is not set # CONFIG_NETFILTER is not set - -# -# DCCP Configuration (EXPERIMENTAL) -# CONFIG_IP_DCCP=m CONFIG_INET_DCCP_DIAG=m CONFIG_IP_DCCP_ACKVEC=y @@ -269,15 +260,7 @@ CONFIG_IP_DCCP_CCID3_RTO=100 # # CONFIG_IP_DCCP_DEBUG is not set # CONFIG_NET_DCCPPROBE is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# # CONFIG_IP_SCTP is not set - -# -# TIPC Configuration (EXPERIMENTAL) -# # CONFIG_TIPC is not set # CONFIG_ATM is not set # CONFIG_BRIDGE is not set @@ -314,6 +297,7 @@ CONFIG_NET_TCPPROBE=m # CONFIG_MAC80211 is not set # CONFIG_IEEE80211 is not set # CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set # # Device Drivers @@ -328,26 +312,10 @@ CONFIG_FW_LOADER=y # CONFIG_DEBUG_DRIVER is not set # CONFIG_DEBUG_DEVRES is not set # CONFIG_SYS_HYPERVISOR is not set - -# -# Connector - unified userspace <-> kernelspace linker -# CONFIG_CONNECTOR=m # CONFIG_MTD is not set - -# -# Parallel port support -# # CONFIG_PARPORT is not set - -# -# Plug and Play support -# -# CONFIG_PNPACPI is not set - -# -# Block devices -# +CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set @@ -364,18 +332,11 @@ CONFIG_CDROM_PKTCDVD=m CONFIG_CDROM_PKTCDVD_BUFFERS=8 CONFIG_CDROM_PKTCDVD_WCACHE=y CONFIG_ATA_OVER_ETH=m - -# -# Misc devices -# +CONFIG_MISC_DEVICES=y # CONFIG_PHANTOM is not set +# CONFIG_EEPROM_93CX6 is not set # CONFIG_SGI_IOC4 is not set # CONFIG_TIFM_CORE is not set -# CONFIG_BLINK is not set - -# -# ATA/ATAPI/MFM/RLL support -# CONFIG_IDE=y CONFIG_BLK_DEV_IDE=y @@ -440,6 +401,7 @@ CONFIG_BLK_DEV_IDEDMA=y # CONFIG_RAID_ATTRS=m CONFIG_SCSI=y +CONFIG_SCSI_DMA=y # CONFIG_SCSI_TGT is not set CONFIG_SCSI_NETLINK=y CONFIG_SCSI_PROC_FS=y @@ -505,7 +467,6 @@ CONFIG_ISCSI_TCP=m # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_DEBUG is not set -# CONFIG_SCSI_ESP_CORE is not set # CONFIG_SCSI_SUNESP is not set # CONFIG_SCSI_SRP is not set # CONFIG_ATA is not set @@ -545,30 +506,16 @@ CONFIG_DM_ZERO=m # # CONFIG_FIREWIRE is not set # CONFIG_IEEE1394 is not set - -# -# I2O device support -# # CONFIG_I2O is not set - -# -# Network device support -# CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set CONFIG_DUMMY=m # CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set - -# -# ARCnet devices -# # CONFIG_ARCNET is not set # CONFIG_PHYLIB is not set - -# -# Ethernet (10 or 100Mbit) -# CONFIG_NET_ETHERNET=y CONFIG_MII=m # CONFIG_SUNLANCE is not set @@ -578,10 +525,6 @@ CONFIG_MII=m # CONFIG_SUNGEM is not set CONFIG_CASSINI=m # CONFIG_NET_VENDOR_3COM is not set - -# -# Tulip family network device support -# # CONFIG_NET_TULIP is not set # CONFIG_HP100 is not set CONFIG_NET_PCI=y @@ -617,7 +560,6 @@ CONFIG_E1000_NAPI=y # CONFIG_SIS190 is not set # CONFIG_SKGE is not set # CONFIG_SKY2 is not set -# CONFIG_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set CONFIG_TIGON3=m CONFIG_BNX2=m @@ -631,11 +573,6 @@ CONFIG_NETDEV_10000=y # CONFIG_MYRI10GE is not set # CONFIG_NETXEN_NIC is not set # CONFIG_MLX4_CORE is not set -CONFIG_MLX4_DEBUG=y - -# -# Token Ring devices -# # CONFIG_TR is not set # @@ -665,6 +602,7 @@ CONFIG_PPP_DEFLATE=m CONFIG_PPP_BSDCOMP=m CONFIG_PPP_MPPE=m CONFIG_PPPOE=m +# CONFIG_PPPOL2TP is not set # CONFIG_SLIP is not set CONFIG_SLHC=m # CONFIG_NET_FC is not set @@ -677,10 +615,6 @@ CONFIG_SLHC=m # ISDN subsystem # # CONFIG_ISDN is not set - -# -# Telephony Support -# # CONFIG_PHONE is not set # @@ -688,6 +622,7 @@ CONFIG_SLHC=m # CONFIG_INPUT=y # CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set # # Userland interfaces @@ -733,7 +668,6 @@ CONFIG_INPUT_SPARCSPKR=y # CONFIG_INPUT_POWERMATE is not set # CONFIG_INPUT_YEALINK is not set # CONFIG_INPUT_UINPUT is not set -# CONFIG_INPUT_POLLDEV is not set # # Hardware I/O ports @@ -773,10 +707,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y # CONFIG_SERIAL_JSM is not set CONFIG_UNIX98_PTYS=y # CONFIG_LEGACY_PTYS is not set - -# -# IPMI -# # CONFIG_IPMI_HANDLER is not set # CONFIG_WATCHDOG is not set # CONFIG_HW_RANDOM is not set @@ -785,10 +715,6 @@ CONFIG_RTC=y # CONFIG_APPLICOM is not set # CONFIG_DRM is not set # CONFIG_RAW_DRIVER is not set - -# -# TPM devices -# # CONFIG_TCG_TPM is not set CONFIG_DEVPORT=y CONFIG_I2C=y @@ -822,6 +748,7 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_SIS5595 is not set # CONFIG_I2C_SIS630 is not set # CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_TAOS_EVM is not set # CONFIG_I2C_STUB is not set # CONFIG_I2C_TINY_USB is not set # CONFIG_I2C_VIA is not set @@ -833,11 +760,13 @@ CONFIG_I2C_ALGOBIT=y # # CONFIG_SENSORS_DS1337 is not set # CONFIG_SENSORS_DS1374 is not set +# CONFIG_DS1682 is not set # CONFIG_SENSORS_EEPROM is not set # CONFIG_SENSORS_PCF8574 is not set # CONFIG_SENSORS_PCA9539 is not set # CONFIG_SENSORS_PCF8591 is not set # CONFIG_SENSORS_MAX6875 is not set +# CONFIG_SENSORS_TSL2550 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set @@ -848,11 +777,8 @@ CONFIG_I2C_ALGOBIT=y # # CONFIG_SPI is not set # CONFIG_SPI_MASTER is not set - -# -# Dallas's 1-wire bus -# # CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set CONFIG_HWMON=y # CONFIG_HWMON_VID is not set # CONFIG_SENSORS_ABITUGURU is not set @@ -949,6 +875,8 @@ CONFIG_FB_TILEBLITTING=y # CONFIG_FB_ASILIANT is not set # CONFIG_FB_IMSTT is not set # CONFIG_FB_SBUS is not set +# CONFIG_FB_XVR500 is not set +# CONFIG_FB_XVR2500 is not set # CONFIG_FB_S1D13XXX is not set # CONFIG_FB_NVIDIA is not set # CONFIG_FB_RIVA is not set @@ -970,9 +898,6 @@ CONFIG_FB_RADEON_I2C=y # CONFIG_FB_TRIDENT is not set # CONFIG_FB_ARK is not set # CONFIG_FB_PM3 is not set -# CONFIG_FB_XVR500 is not set -# CONFIG_FB_XVR2500 is not set -# CONFIG_FB_PCI is not set # CONFIG_FB_VIRTUAL is not set # @@ -1118,10 +1043,7 @@ CONFIG_SND_SUN_CS4231=m # # CONFIG_SOUND_PRIME is not set CONFIG_AC97_BUS=m - -# -# HID Devices -# +CONFIG_HID_SUPPORT=y CONFIG_HID=y # CONFIG_HID_DEBUG is not set @@ -1132,10 +1054,7 @@ CONFIG_USB_HID=y # CONFIG_USB_HIDINPUT_POWERBOOK is not set # CONFIG_HID_FF is not set CONFIG_USB_HIDDEV=y - -# -# USB support -# +CONFIG_USB_SUPPORT=y CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB_ARCH_HAS_OHCI=y CONFIG_USB_ARCH_HAS_EHCI=y @@ -1157,7 +1076,6 @@ CONFIG_USB_EHCI_HCD=m # CONFIG_USB_EHCI_SPLIT_ISO is not set # CONFIG_USB_EHCI_ROOT_HUB_TT is not set # CONFIG_USB_EHCI_TT_NEWSCHED is not set -# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set # CONFIG_USB_ISP116X_HCD is not set CONFIG_USB_OHCI_HCD=y # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set @@ -1165,6 +1083,7 @@ CONFIG_USB_OHCI_HCD=y CONFIG_USB_OHCI_LITTLE_ENDIAN=y CONFIG_USB_UHCI_HCD=m # CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set # # USB Device Class drivers @@ -1256,17 +1175,9 @@ CONFIG_USB_STORAGE=m # # LED Triggers # - -# -# InfiniBand support -# # CONFIG_INFINIBAND is not set # -# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) -# - -# # Real Time Clock # # CONFIG_RTC_CLASS is not set @@ -1387,7 +1298,6 @@ CONFIG_RAMFS=y # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set -# CONFIG_9P_FS is not set # # Partition Types @@ -1465,8 +1375,10 @@ CONFIG_DEBUG_FS=y CONFIG_DEBUG_KERNEL=y # CONFIG_DEBUG_SHIRQ is not set CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHED_DEBUG is not set CONFIG_SCHEDSTATS=y # CONFIG_TIMER_STATS is not set +# CONFIG_SLUB_DEBUG_ON is not set # CONFIG_DEBUG_RT_MUTEXES is not set # CONFIG_RT_MUTEX_TESTER is not set # CONFIG_DEBUG_SPINLOCK is not set @@ -1496,10 +1408,10 @@ CONFIG_FORCED_INLINING=y CONFIG_KEYS=y # CONFIG_KEYS_DEBUG_PROC_KEYS is not set # CONFIG_SECURITY is not set - -# -# Cryptographic options -# +CONFIG_XOR_BLOCKS=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m CONFIG_CRYPTO=y CONFIG_CRYPTO_ALGAPI=y CONFIG_CRYPTO_BLKCIPHER=y @@ -1539,10 +1451,7 @@ CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_CRC32C=m CONFIG_CRYPTO_CAMELLIA=m CONFIG_CRYPTO_TEST=m - -# -# Hardware crypto devices -# +CONFIG_CRYPTO_HW=y # # Library routines diff --git a/arch/sparc64/kernel/ds.c b/arch/sparc64/kernel/ds.c index 1c587107cef..fa1f04d756a 100644 --- a/arch/sparc64/kernel/ds.c +++ b/arch/sparc64/kernel/ds.c @@ -228,7 +228,7 @@ static struct ds_cap_state *find_cap_by_string(const char *name) return NULL; } -static int ds_send(struct ldc_channel *lp, void *data, int len) +static int __ds_send(struct ldc_channel *lp, void *data, int len) { int err, limit = 1000; @@ -243,6 +243,18 @@ static int ds_send(struct ldc_channel *lp, void *data, int len) return err; } +static int ds_send(struct ldc_channel *lp, void *data, int len) +{ + unsigned long flags; + int err; + + spin_lock_irqsave(&ds_lock, flags); + err = __ds_send(lp, data, len); + spin_unlock_irqrestore(&ds_lock, flags); + + return err; +} + struct ds_md_update_req { __u64 req_num; }; @@ -267,6 +279,8 @@ static void md_update_data(struct ldc_channel *lp, printk(KERN_INFO PFX "Machine description update.\n"); + mdesc_update(); + memset(&pkt, 0, sizeof(pkt)); pkt.data.tag.type = DS_DATA; pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag); @@ -275,8 +289,6 @@ static void md_update_data(struct ldc_channel *lp, pkt.res.result = DS_OK; ds_send(lp, &pkt, sizeof(pkt)); - - mdesc_update(); } struct ds_shutdown_req { @@ -391,18 +403,6 @@ struct dr_cpu_resp_entry { __u32 str_off; }; -/* DR cpu requests get queued onto the work list by the - * dr_cpu_data() callback. The list is protected by - * ds_lock, and processed by dr_cpu_process() in order. - */ -static LIST_HEAD(dr_cpu_work_list); -static DECLARE_WAIT_QUEUE_HEAD(dr_cpu_wait); - -struct dr_cpu_queue_entry { - struct list_head list; - char req[0]; -}; - static void __dr_cpu_send_error(struct ds_cap_state *cp, struct ds_data *data) { struct dr_cpu_tag *tag = (struct dr_cpu_tag *) (data + 1); @@ -425,7 +425,7 @@ static void __dr_cpu_send_error(struct ds_cap_state *cp, struct ds_data *data) pkt.data.tag.len = msg_len - sizeof(struct ds_msg_tag); - ds_send(dp->lp, &pkt, msg_len); + __ds_send(dp->lp, &pkt, msg_len); } static void dr_cpu_send_error(struct ds_cap_state *cp, struct ds_data *data) @@ -555,7 +555,7 @@ static int dr_cpu_configure(struct ds_cap_state *cp, u64 req_num, } spin_lock_irqsave(&ds_lock, flags); - ds_send(ds_info->lp, resp, resp_len); + __ds_send(ds_info->lp, resp, resp_len); spin_unlock_irqrestore(&ds_lock, flags); kfree(resp); @@ -596,7 +596,7 @@ static int dr_cpu_unconfigure(struct ds_cap_state *cp, u64 req_num, } spin_lock_irqsave(&ds_lock, flags); - ds_send(ds_info->lp, resp, resp_len); + __ds_send(ds_info->lp, resp, resp_len); spin_unlock_irqrestore(&ds_lock, flags); kfree(resp); @@ -604,107 +604,49 @@ static int dr_cpu_unconfigure(struct ds_cap_state *cp, u64 req_num, return 0; } -static void process_dr_cpu_list(struct ds_cap_state *cp) +static void dr_cpu_data(struct ldc_channel *lp, + struct ds_cap_state *cp, + void *buf, int len) { - struct dr_cpu_queue_entry *qp, *tmp; - unsigned long flags; - LIST_HEAD(todo); + struct ds_data *data = buf; + struct dr_cpu_tag *tag = (struct dr_cpu_tag *) (data + 1); + u32 *cpu_list = (u32 *) (tag + 1); + u64 req_num = tag->req_num; cpumask_t mask; + unsigned int i; + int err; - spin_lock_irqsave(&ds_lock, flags); - list_splice(&dr_cpu_work_list, &todo); - INIT_LIST_HEAD(&dr_cpu_work_list); - spin_unlock_irqrestore(&ds_lock, flags); - - list_for_each_entry_safe(qp, tmp, &todo, list) { - struct ds_data *data = (struct ds_data *) qp->req; - struct dr_cpu_tag *tag = (struct dr_cpu_tag *) (data + 1); - u32 *cpu_list = (u32 *) (tag + 1); - u64 req_num = tag->req_num; - unsigned int i; - int err; - - switch (tag->type) { - case DR_CPU_CONFIGURE: - case DR_CPU_UNCONFIGURE: - case DR_CPU_FORCE_UNCONFIGURE: - break; - - default: - dr_cpu_send_error(cp, data); - goto next; - } - - purge_dups(cpu_list, tag->num_records); - - cpus_clear(mask); - for (i = 0; i < tag->num_records; i++) { - if (cpu_list[i] == CPU_SENTINEL) - continue; - - if (cpu_list[i] < NR_CPUS) - cpu_set(cpu_list[i], mask); - } - - if (tag->type == DR_CPU_CONFIGURE) - err = dr_cpu_configure(cp, req_num, &mask); - else - err = dr_cpu_unconfigure(cp, req_num, &mask); - - if (err) - dr_cpu_send_error(cp, data); + switch (tag->type) { + case DR_CPU_CONFIGURE: + case DR_CPU_UNCONFIGURE: + case DR_CPU_FORCE_UNCONFIGURE: + break; -next: - list_del(&qp->list); - kfree(qp); + default: + dr_cpu_send_error(cp, data); + return; } -} -static int dr_cpu_thread(void *__unused) -{ - struct ds_cap_state *cp; - DEFINE_WAIT(wait); + purge_dups(cpu_list, tag->num_records); - cp = find_cap_by_string("dr-cpu"); - - while (1) { - prepare_to_wait(&dr_cpu_wait, &wait, TASK_INTERRUPTIBLE); - if (list_empty(&dr_cpu_work_list)) - schedule(); - finish_wait(&dr_cpu_wait, &wait); - - if (kthread_should_stop()) - break; + cpus_clear(mask); + for (i = 0; i < tag->num_records; i++) { + if (cpu_list[i] == CPU_SENTINEL) + continue; - process_dr_cpu_list(cp); + if (cpu_list[i] < NR_CPUS) + cpu_set(cpu_list[i], mask); } - return 0; -} - -static void dr_cpu_data(struct ldc_channel *lp, - struct ds_cap_state *dp, - void *buf, int len) -{ - struct dr_cpu_queue_entry *qp; - struct ds_data *dpkt = buf; - struct dr_cpu_tag *rp; - - rp = (struct dr_cpu_tag *) (dpkt + 1); + if (tag->type == DR_CPU_CONFIGURE) + err = dr_cpu_configure(cp, req_num, &mask); + else + err = dr_cpu_unconfigure(cp, req_num, &mask); - qp = kmalloc(sizeof(struct dr_cpu_queue_entry) + len, GFP_ATOMIC); - if (!qp) { - struct ds_cap_state *cp; - - cp = find_cap_by_string("dr-cpu"); - __dr_cpu_send_error(cp, dpkt); - } else { - memcpy(&qp->req, buf, len); - list_add_tail(&qp->list, &dr_cpu_work_list); - wake_up(&dr_cpu_wait); - } + if (err) + dr_cpu_send_error(cp, data); } -#endif +#endif /* CONFIG_HOTPLUG_CPU */ struct ds_pri_msg { __u64 req_num; @@ -820,7 +762,7 @@ void ldom_set_var(const char *var, const char *value) ds_var_doorbell = 0; ds_var_response = -1; - ds_send(dp->lp, &pkt, msg_len); + __ds_send(dp->lp, &pkt, msg_len); spin_unlock_irqrestore(&ds_lock, flags); loops = 1000; @@ -904,7 +846,7 @@ static int register_services(struct ds_info *dp) pbuf.req.minor = 0; strcpy(pbuf.req.svc_id, cp->service_id); - err = ds_send(lp, &pbuf, msg_len); + err = __ds_send(lp, &pbuf, msg_len); if (err > 0) cp->state = CAP_STATE_REG_SENT; } @@ -960,27 +902,97 @@ conn_reset: return -ECONNRESET; } +static void __send_ds_nack(struct ds_info *dp, u64 handle) +{ + struct ds_data_nack nack = { + .tag = { + .type = DS_NACK, + .len = (sizeof(struct ds_data_nack) - + sizeof(struct ds_msg_tag)), + }, + .handle = handle, + .result = DS_INV_HDL, + }; + + __ds_send(dp->lp, &nack, sizeof(nack)); +} + +static LIST_HEAD(ds_work_list); +static DECLARE_WAIT_QUEUE_HEAD(ds_wait); + +struct ds_queue_entry { + struct list_head list; + int req_len; + int __pad; + u64 req[0]; +}; + +static void process_ds_work(void) +{ + struct ds_queue_entry *qp, *tmp; + static struct ds_info *dp; + unsigned long flags; + LIST_HEAD(todo); + + spin_lock_irqsave(&ds_lock, flags); + list_splice(&ds_work_list, &todo); + INIT_LIST_HEAD(&ds_work_list); + spin_unlock_irqrestore(&ds_lock, flags); + + dp = ds_info; + + list_for_each_entry_safe(qp, tmp, &todo, list) { + struct ds_data *dpkt = (struct ds_data *) qp->req; + struct ds_cap_state *cp = find_cap(dpkt->handle); + int req_len = qp->req_len; + + if (!cp) { + printk(KERN_ERR PFX "Data for unknown handle %lu\n", + dpkt->handle); + + spin_lock_irqsave(&ds_lock, flags); + __send_ds_nack(dp, dpkt->handle); + spin_unlock_irqrestore(&ds_lock, flags); + } else { + cp->data(dp->lp, cp, dpkt, req_len); + } + + list_del(&qp->list); + kfree(qp); + } +} + +static int ds_thread(void *__unused) +{ + DEFINE_WAIT(wait); + + while (1) { + prepare_to_wait(&ds_wait, &wait, TASK_INTERRUPTIBLE); + if (list_empty(&ds_work_list)) + schedule(); + finish_wait(&ds_wait, &wait); + + if (kthread_should_stop()) + break; + + process_ds_work(); + } + + return 0; +} + static int ds_data(struct ds_info *dp, struct ds_msg_tag *pkt, int len) { struct ds_data *dpkt = (struct ds_data *) pkt; - struct ds_cap_state *cp = find_cap(dpkt->handle); - - if (!cp) { - struct ds_data_nack nack = { - .tag = { - .type = DS_NACK, - .len = (sizeof(struct ds_data_nack) - - sizeof(struct ds_msg_tag)), - }, - .handle = dpkt->handle, - .result = DS_INV_HDL, - }; - - printk(KERN_ERR PFX "Data for unknown handle %lu\n", - dpkt->handle); - ds_send(dp->lp, &nack, sizeof(nack)); + struct ds_queue_entry *qp; + + qp = kmalloc(sizeof(struct ds_queue_entry) + len, GFP_ATOMIC); + if (!qp) { + __send_ds_nack(dp, dpkt->handle); } else { - cp->data(dp->lp, cp, dpkt, len); + memcpy(&qp->req, pkt, len); + list_add_tail(&qp->list, &ds_work_list); + wake_up(&ds_wait); } return 0; } @@ -996,11 +1008,24 @@ static void ds_up(struct ds_info *dp) req.ver.major = 1; req.ver.minor = 0; - err = ds_send(lp, &req, sizeof(req)); + err = __ds_send(lp, &req, sizeof(req)); if (err > 0) dp->hs_state = DS_HS_START; } +static void ds_reset(struct ds_info *dp) +{ + int i; + + dp->hs_state = 0; + + for (i = 0; i < ARRAY_SIZE(ds_states); i++) { + struct ds_cap_state *cp = &ds_states[i]; + + cp->state = CAP_STATE_UNKNOWN; + } +} + static void ds_event(void *arg, int event) { struct ds_info *dp = arg; @@ -1016,6 +1041,12 @@ static void ds_event(void *arg, int event) return; } + if (event == LDC_EVENT_RESET) { + ds_reset(dp); + spin_unlock_irqrestore(&ds_lock, flags); + return; + } + if (event != LDC_EVENT_DATA_READY) { printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event); spin_unlock_irqrestore(&ds_lock, flags); @@ -1148,9 +1179,7 @@ static int __init ds_init(void) for (i = 0; i < ARRAY_SIZE(ds_states); i++) ds_states[i].handle = ((u64)i << 32); -#ifdef CONFIG_HOTPLUG_CPU - kthread_run(dr_cpu_thread, NULL, "kdrcpud"); -#endif + kthread_run(ds_thread, NULL, "kldomd"); return vio_register_driver(&ds_driver); } diff --git a/arch/sparc64/kernel/hvtramp.S b/arch/sparc64/kernel/hvtramp.S index 76a090e2c2a..a55c252e18c 100644 --- a/arch/sparc64/kernel/hvtramp.S +++ b/arch/sparc64/kernel/hvtramp.S @@ -10,6 +10,7 @@ #include <asm/hvtramp.h> #include <asm/pstate.h> #include <asm/ptrace.h> +#include <asm/head.h> #include <asm/asi.h> .text @@ -28,7 +29,7 @@ * First setup basic privileged cpu state. */ hv_cpu_startup: - wrpr %g0, 0, %gl + SET_GL(0) wrpr %g0, 15, %pil wrpr %g0, 0, %canrestore wrpr %g0, 0, %otherwin diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c index 62a38979394..302ba5e5a0b 100644 --- a/arch/sparc64/kernel/mdesc.c +++ b/arch/sparc64/kernel/mdesc.c @@ -137,7 +137,7 @@ static struct mdesc_handle *mdesc_kmalloc(unsigned int mdesc_size) sizeof(struct mdesc_hdr) + mdesc_size); - base = kmalloc(handle_size + 15, GFP_KERNEL); + base = kmalloc(handle_size + 15, GFP_KERNEL | __GFP_NOFAIL); if (base) { struct mdesc_handle *hp; unsigned long addr; @@ -214,18 +214,83 @@ void mdesc_release(struct mdesc_handle *hp) } EXPORT_SYMBOL(mdesc_release); -static void do_mdesc_update(struct work_struct *work) +static DEFINE_MUTEX(mdesc_mutex); +static struct mdesc_notifier_client *client_list; + +void mdesc_register_notifier(struct mdesc_notifier_client *client) +{ + u64 node; + + mutex_lock(&mdesc_mutex); + client->next = client_list; + client_list = client; + + mdesc_for_each_node_by_name(cur_mdesc, node, client->node_name) + client->add(cur_mdesc, node); + + mutex_unlock(&mdesc_mutex); +} + +/* Run 'func' on nodes which are in A but not in B. */ +static void invoke_on_missing(const char *name, + struct mdesc_handle *a, + struct mdesc_handle *b, + void (*func)(struct mdesc_handle *, u64)) +{ + u64 node; + + mdesc_for_each_node_by_name(a, node, name) { + const u64 *id = mdesc_get_property(a, node, "id", NULL); + int found = 0; + u64 fnode; + + mdesc_for_each_node_by_name(b, fnode, name) { + const u64 *fid = mdesc_get_property(b, fnode, + "id", NULL); + + if (*id == *fid) { + found = 1; + break; + } + } + if (!found) + func(a, node); + } +} + +static void notify_one(struct mdesc_notifier_client *p, + struct mdesc_handle *old_hp, + struct mdesc_handle *new_hp) +{ + invoke_on_missing(p->node_name, old_hp, new_hp, p->remove); + invoke_on_missing(p->node_name, new_hp, old_hp, p->add); +} + +static void mdesc_notify_clients(struct mdesc_handle *old_hp, + struct mdesc_handle *new_hp) +{ + struct mdesc_notifier_client *p = client_list; + + while (p) { + notify_one(p, old_hp, new_hp); + p = p->next; + } +} + +void mdesc_update(void) { unsigned long len, real_len, status; struct mdesc_handle *hp, *orig_hp; unsigned long flags; + mutex_lock(&mdesc_mutex); + (void) sun4v_mach_desc(0UL, 0UL, &len); hp = mdesc_alloc(len, &kmalloc_mdesc_memops); if (!hp) { printk(KERN_ERR "MD: mdesc alloc fails\n"); - return; + goto out; } status = sun4v_mach_desc(__pa(&hp->mdesc), len, &real_len); @@ -234,25 +299,25 @@ static void do_mdesc_update(struct work_struct *work) status); atomic_dec(&hp->refcnt); mdesc_free(hp); - return; + goto out; } spin_lock_irqsave(&mdesc_lock, flags); orig_hp = cur_mdesc; cur_mdesc = hp; + spin_unlock_irqrestore(&mdesc_lock, flags); + mdesc_notify_clients(orig_hp, hp); + + spin_lock_irqsave(&mdesc_lock, flags); if (atomic_dec_and_test(&orig_hp->refcnt)) mdesc_free(orig_hp); else list_add(&orig_hp->list, &mdesc_zombie_list); spin_unlock_irqrestore(&mdesc_lock, flags); -} - -static DECLARE_WORK(mdesc_update_work, do_mdesc_update); -void mdesc_update(void) -{ - schedule_work(&mdesc_update_work); +out: + mutex_unlock(&mdesc_mutex); } static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc) @@ -278,13 +343,14 @@ u64 mdesc_node_by_name(struct mdesc_handle *hp, u64 last_node = hp->mdesc.node_sz / 16; u64 ret; - if (from_node == MDESC_NODE_NULL) - from_node = 0; - - if (from_node >= last_node) + if (from_node == MDESC_NODE_NULL) { + ret = from_node = 0; + } else if (from_node >= last_node) { return MDESC_NODE_NULL; + } else { + ret = ep[from_node].d.val; + } - ret = ep[from_node].d.val; while (ret < last_node) { if (ep[ret].tag != MD_NODE) return MDESC_NODE_NULL; diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index dc928e49e34..aafde3dd9fd 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -454,9 +454,9 @@ static int show_cpuinfo(struct seq_file *m, void *__unused) ncpus_probed, num_online_cpus(), dcache_parity_tl1_occurred, - icache_parity_tl1_occurred, + icache_parity_tl1_occurred #ifndef CONFIG_SMP - cpu_data(0).clock_tick + , cpu_data(0).clock_tick #endif ); #ifdef CONFIG_SMP diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c index 203e8730100..fb13775b368 100644 --- a/arch/sparc64/kernel/signal.c +++ b/arch/sparc64/kernel/signal.c @@ -289,9 +289,7 @@ void do_rt_sigreturn(struct pt_regs *regs) struct rt_signal_frame __user *sf; unsigned long tpc, tnpc, tstate; __siginfo_fpu_t __user *fpu_save; - mm_segment_t old_fs; sigset_t set; - stack_t st; int err; /* Always make any pending restarted system calls return -EINTR */ @@ -327,20 +325,13 @@ void do_rt_sigreturn(struct pt_regs *regs) err |= restore_fpu_state(regs, &sf->fpu_state); err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t)); - err |= __copy_from_user(&st, &sf->stack, sizeof(stack_t)); - + err |= do_sigaltstack(&sf->stack, NULL, (unsigned long)sf); + if (err) goto segv; - + regs->tpc = tpc; regs->tnpc = tnpc; - - /* It is more difficult to avoid calling this function than to - call it and ignore errors. */ - old_fs = get_fs(); - set_fs(KERNEL_DS); - do_sigaltstack((const stack_t __user *) &st, NULL, (unsigned long)sf); - set_fs(old_fs); sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index 00a9e3286c8..6ef2d299fb1 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -2225,6 +2225,7 @@ void die_if_kernel(char *str, struct pt_regs *regs) notify_die(DIE_OOPS, str, regs, 0, 255, SIGSEGV); __asm__ __volatile__("flushw"); __show_regs(regs); + add_taint(TAINT_DIE); if (regs->tstate & TSTATE_PRIV) { struct reg_window *rw = (struct reg_window *) (regs->u_regs[UREG_FP] + STACK_BIAS); diff --git a/arch/sparc64/kernel/vio.c b/arch/sparc64/kernel/vio.c index 49569b44ea1..8d3cc4fdb55 100644 --- a/arch/sparc64/kernel/vio.c +++ b/arch/sparc64/kernel/vio.c @@ -201,10 +201,11 @@ static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp, static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, struct device *parent) { - const char *type, *compat; + const char *type, *compat, *bus_id_name; struct device_node *dp; struct vio_dev *vdev; int err, tlen, clen; + const u64 *id; type = mdesc_get_property(hp, mp, "device-type", &tlen); if (!type) { @@ -220,6 +221,16 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, return NULL; } + bus_id_name = type; + if (!strcmp(type, "domain-services-port")) + bus_id_name = "ds"; + + if (strlen(bus_id_name) >= KOBJ_NAME_LEN - 4) { + printk(KERN_ERR "VIO: bus_id_name [%s] is too long.\n", + bus_id_name); + return NULL; + } + compat = mdesc_get_property(hp, mp, "device-type", &clen); if (!compat) { clen = 0; @@ -249,7 +260,14 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, vio_fill_channel_info(hp, mp, vdev); - snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%lx", mp); + id = mdesc_get_property(hp, mp, "id", NULL); + if (!id) + snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s", + bus_id_name); + else + snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu", + bus_id_name, *id); + vdev->dev.parent = parent; vdev->dev.bus = &vio_bus_type; vdev->dev.release = vio_dev_release; @@ -269,6 +287,8 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, } vdev->dp = dp; + printk(KERN_ERR "VIO: Adding device %s\n", vdev->dev.bus_id); + err = device_register(&vdev->dev); if (err) { printk(KERN_ERR "VIO: Could not register device %s, err=%d\n", @@ -283,46 +303,46 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, return vdev; } -static void walk_tree(struct mdesc_handle *hp, u64 n, struct vio_dev *parent) +static void vio_add(struct mdesc_handle *hp, u64 node) { - u64 a; - - mdesc_for_each_arc(a, hp, n, MDESC_ARC_TYPE_FWD) { - struct vio_dev *vdev; - u64 target; - - target = mdesc_arc_target(hp, a); - vdev = vio_create_one(hp, target, &parent->dev); - if (vdev) - walk_tree(hp, target, vdev); - } + (void) vio_create_one(hp, node, &root_vdev->dev); } -static void create_devices(struct mdesc_handle *hp, u64 root) +static int vio_md_node_match(struct device *dev, void *arg) { - u64 mp; + struct vio_dev *vdev = to_vio_dev(dev); - root_vdev = vio_create_one(hp, root, NULL); - if (!root_vdev) { - printk(KERN_ERR "VIO: Coult not create root device.\n"); - return; - } + if (vdev->mp == (u64) arg) + return 1; - walk_tree(hp, root, root_vdev); + return 0; +} + +static void vio_remove(struct mdesc_handle *hp, u64 node) +{ + struct device *dev; - /* Domain services is odd as it doesn't sit underneath the - * channel-devices node, so we plug it in manually. - */ - mp = mdesc_node_by_name(hp, MDESC_NODE_NULL, "domain-services"); - if (mp != MDESC_NODE_NULL) { - struct vio_dev *parent = vio_create_one(hp, mp, - &root_vdev->dev); + dev = device_find_child(&root_vdev->dev, (void *) node, + vio_md_node_match); + if (dev) { + printk(KERN_INFO "VIO: Removing device %s\n", dev->bus_id); - if (parent) - walk_tree(hp, mp, parent); + device_unregister(dev); } } +static struct mdesc_notifier_client vio_device_notifier = { + .add = vio_add, + .remove = vio_remove, + .node_name = "virtual-device-port", +}; + +static struct mdesc_notifier_client vio_ds_notifier = { + .add = vio_add, + .remove = vio_remove, + .node_name = "domain-services-port", +}; + const char *channel_devices_node = "channel-devices"; const char *channel_devices_compat = "SUNW,sun4v-channel-devices"; const char *cfg_handle_prop = "cfg-handle"; @@ -381,11 +401,19 @@ static int __init vio_init(void) cdev_cfg_handle = *cfg_handle; - create_devices(hp, root); + root_vdev = vio_create_one(hp, root, NULL); + err = -ENODEV; + if (!root_vdev) { + printk(KERN_ERR "VIO: Coult not create root device.\n"); + goto out_release; + } + + mdesc_register_notifier(&vio_device_notifier); + mdesc_register_notifier(&vio_ds_notifier); mdesc_release(hp); - return 0; + return err; out_release: mdesc_release(hp); diff --git a/arch/sparc64/kernel/viohs.c b/arch/sparc64/kernel/viohs.c index 15613add45d..09126fc338b 100644 --- a/arch/sparc64/kernel/viohs.c +++ b/arch/sparc64/kernel/viohs.c @@ -78,6 +78,24 @@ static int start_handshake(struct vio_driver_state *vio) return 0; } +static void flush_rx_dring(struct vio_driver_state *vio) +{ + struct vio_dring_state *dr; + u64 ident; + + BUG_ON(!(vio->dr_state & VIO_DR_STATE_RXREG)); + + dr = &vio->drings[VIO_DRIVER_RX_RING]; + ident = dr->ident; + + BUG_ON(!vio->desc_buf); + kfree(vio->desc_buf); + vio->desc_buf = NULL; + + memset(dr, 0, sizeof(*dr)); + dr->ident = ident; +} + void vio_link_state_change(struct vio_driver_state *vio, int event) { if (event == LDC_EVENT_UP) { @@ -98,6 +116,16 @@ void vio_link_state_change(struct vio_driver_state *vio, int event) break; } start_handshake(vio); + } else if (event == LDC_EVENT_RESET) { + vio->hs_state = VIO_HS_INVALID; + + if (vio->dr_state & VIO_DR_STATE_RXREG) + flush_rx_dring(vio); + + vio->dr_state = 0x00; + memset(&vio->ver, 0, sizeof(vio->ver)); + + ldc_disconnect(vio->lp); } } EXPORT_SYMBOL(vio_link_state_change); @@ -396,6 +424,8 @@ static int process_dreg_info(struct vio_driver_state *vio, if (vio->dr_state & VIO_DR_STATE_RXREG) goto send_nack; + BUG_ON(vio->desc_buf); + vio->desc_buf = kzalloc(pkt->descr_size, GFP_ATOMIC); if (!vio->desc_buf) goto send_nack; diff --git a/arch/sparc64/kernel/vmlinux.lds.S b/arch/sparc64/kernel/vmlinux.lds.S index 3ad10f3027e..481861764de 100644 --- a/arch/sparc64/kernel/vmlinux.lds.S +++ b/arch/sparc64/kernel/vmlinux.lds.S @@ -90,10 +90,8 @@ SECTIONS __initramfs_end = .; #endif - . = ALIGN(PAGE_SIZE); - __per_cpu_start = .; - .data.percpu : { *(.data.percpu) } - __per_cpu_end = .; + PERCPU(PAGE_SIZE) + . = ALIGN(PAGE_SIZE); __init_end = .; __bss_start = .; diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c index b582024d219..17123e9ecf7 100644 --- a/arch/sparc64/mm/fault.c +++ b/arch/sparc64/mm/fault.c @@ -278,7 +278,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) struct mm_struct *mm = current->mm; struct vm_area_struct *vma; unsigned int insn = 0; - int si_code, fault_code; + int si_code, fault_code, fault; unsigned long address, mm_rss; fault_code = get_thread_fault_code(); @@ -415,20 +415,18 @@ good_area: goto bad_area; } - switch (handle_mm_fault(mm, vma, address, (fault_code & FAULT_CODE_WRITE))) { - case VM_FAULT_MINOR: - current->min_flt++; - break; - case VM_FAULT_MAJOR: - current->maj_flt++; - break; - case VM_FAULT_SIGBUS: - goto do_sigbus; - case VM_FAULT_OOM: - goto out_of_memory; - default: + fault = handle_mm_fault(mm, vma, address, (fault_code & FAULT_CODE_WRITE)); + if (unlikely(fault & VM_FAULT_ERROR)) { + if (fault & VM_FAULT_OOM) + goto out_of_memory; + else if (fault & VM_FAULT_SIGBUS) + goto do_sigbus; BUG(); } + if (fault & VM_FAULT_MAJOR) + current->maj_flt++; + else + current->min_flt++; up_read(&mm->mmap_sem); diff --git a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c index e94f6e5d945..7736411f244 100644 --- a/arch/sparc64/solaris/socksys.c +++ b/arch/sparc64/solaris/socksys.c @@ -199,6 +199,5 @@ int __init init_socksys(void) void __exit cleanup_socksys(void) { - if (unregister_chrdev(30, "socksys")) - printk ("Couldn't unregister socksys character device\n"); + unregister_chrdev(30, "socksys"); } |