提交 a24e3d41 编写于 作者: L Linus Torvalds

Merge branch 'akpm' (patches from Andrew)

Merge third patch-bomb from Andrew Morton:

 - more ocfs2 changes

 - a few hotfixes

 - Andy's compat cleanups

 - misc fixes to fatfs, ptrace, coredump, cpumask, creds, eventfd,
   panic, ipmi, kgdb, profile, kfifo, ubsan, etc.

 - many rapidio updates: fixes, new drivers.

 - kcov: kernel code coverage feature.  Like gcov, but not
   "prohibitively expensive".

 - extable code consolidation for various archs

* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (81 commits)
  ia64/extable: use generic search and sort routines
  x86/extable: use generic search and sort routines
  s390/extable: use generic search and sort routines
  alpha/extable: use generic search and sort routines
  kernel/...: convert pr_warning to pr_warn
  drivers: dma-coherent: use memset_io for DMA_MEMORY_IO mappings
  drivers: dma-coherent: use MEMREMAP_WC for DMA_MEMORY_MAP
  memremap: add MEMREMAP_WC flag
  memremap: don't modify flags
  kernel/signal.c: add compile-time check for __ARCH_SI_PREAMBLE_SIZE
  mm/mprotect.c: don't imply PROT_EXEC on non-exec fs
  ipc/sem: make semctl setting sempid consistent
  ubsan: fix tree-wide -Wmaybe-uninitialized false positives
  kfifo: fix sparse complaints
  scripts/gdb: account for changes in module data structure
  scripts/gdb: add cmdline reader command
  scripts/gdb: add version command
  kernel: add kcov code coverage
  profile: hide unused functions when !CONFIG_PROC_FS
  hpwdt: use nmi_panic() when kernel panics in NMI handler
  ...
OCFS2 online file check
-----------------------
This document will describe OCFS2 online file check feature.
Introduction
============
OCFS2 is often used in high-availaibility systems. However, OCFS2 usually
converts the filesystem to read-only when encounters an error. This may not be
necessary, since turning the filesystem read-only would affect other running
processes as well, decreasing availability.
Then, a mount option (errors=continue) is introduced, which would return the
-EIO errno to the calling process and terminate furhter processing so that the
filesystem is not corrupted further. The filesystem is not converted to
read-only, and the problematic file's inode number is reported in the kernel
log. The user can try to check/fix this file via online filecheck feature.
Scope
=====
This effort is to check/fix small issues which may hinder day-to-day operations
of a cluster filesystem by turning the filesystem read-only. The scope of
checking/fixing is at the file level, initially for regular files and eventually
to all files (including system files) of the filesystem.
In case of directory to file links is incorrect, the directory inode is
reported as erroneous.
This feature is not suited for extravagant checks which involve dependency of
other components of the filesystem, such as but not limited to, checking if the
bits for file blocks in the allocation has been set. In case of such an error,
the offline fsck should/would be recommended.
Finally, such an operation/feature should not be automated lest the filesystem
may end up with more damage than before the repair attempt. So, this has to
be performed using user interaction and consent.
User interface
==============
When there are errors in the OCFS2 filesystem, they are usually accompanied
by the inode number which caused the error. This inode number would be the
input to check/fix the file.
There is a sysfs directory for each OCFS2 file system mounting:
/sys/fs/ocfs2/<devname>/filecheck
Here, <devname> indicates the name of OCFS2 volumn device which has been already
mounted. The file above would accept inode numbers. This could be used to
communicate with kernel space, tell which file(inode number) will be checked or
fixed. Currently, three operations are supported, which includes checking
inode, fixing inode and setting the size of result record history.
1. If you want to know what error exactly happened to <inode> before fixing, do
# echo "<inode>" > /sys/fs/ocfs2/<devname>/filecheck/check
# cat /sys/fs/ocfs2/<devname>/filecheck/check
The output is like this:
INO DONE ERROR
39502 1 GENERATION
<INO> lists the inode numbers.
<DONE> indicates whether the operation has been finished.
<ERROR> says what kind of errors was found. For the detailed error numbers,
please refer to the file linux/fs/ocfs2/filecheck.h.
2. If you determine to fix this inode, do
# echo "<inode>" > /sys/fs/ocfs2/<devname>/filecheck/fix
# cat /sys/fs/ocfs2/<devname>/filecheck/fix
The output is like this:
INO DONE ERROR
39502 1 SUCCESS
This time, the <ERROR> column indicates whether this fix is successful or not.
3. The record cache is used to store the history of check/fix results. It's
defalut size is 10, and can be adjust between the range of 10 ~ 100. You can
adjust the size like this:
# echo "<size>" > /sys/fs/ocfs2/<devname>/filecheck/set
Fixing stuff
============
On receivng the inode, the filesystem would read the inode and the
file metadata. In case of errors, the filesystem would fix the errors
and report the problems it fixed in the kernel log. As a precautionary measure,
the inode must first be checked for errors before performing a final fix.
The inode and the result history will be maintained temporarily in a
small linked list buffer which would contain the last (N) inodes
fixed/checked, the detailed errors which were fixed/checked are printed in the
kernel log.
......@@ -56,9 +56,10 @@ iocharset=<name> -- Character set to use for converting between the
you should consider the following option instead.
utf8=<bool> -- UTF-8 is the filesystem safe version of Unicode that
is used by the console. It can be enabled for the
filesystem with this option. If 'uni_xlate' gets set,
UTF-8 gets disabled.
is used by the console. It can be enabled or disabled
for the filesystem with this option.
If 'uni_xlate' gets set, UTF-8 gets disabled.
By default, FAT_DEFAULT_UTF8 setting is used.
uni_xlate=<bool> -- Translate unhandled Unicode characters to special
escaped sequences. This would let you backup and
......
kcov: code coverage for fuzzing
===============================
kcov exposes kernel code coverage information in a form suitable for coverage-
guided fuzzing (randomized testing). Coverage data of a running kernel is
exported via the "kcov" debugfs file. Coverage collection is enabled on a task
basis, and thus it can capture precise coverage of a single system call.
Note that kcov does not aim to collect as much coverage as possible. It aims
to collect more or less stable coverage that is function of syscall inputs.
To achieve this goal it does not collect coverage in soft/hard interrupts
and instrumentation of some inherently non-deterministic parts of kernel is
disbled (e.g. scheduler, locking).
Usage:
======
Configure kernel with:
CONFIG_KCOV=y
CONFIG_KCOV requires gcc built on revision 231296 or later.
Profiling data will only become accessible once debugfs has been mounted:
mount -t debugfs none /sys/kernel/debug
The following program demonstrates kcov usage from within a test program:
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#define KCOV_INIT_TRACE _IOR('c', 1, unsigned long)
#define KCOV_ENABLE _IO('c', 100)
#define KCOV_DISABLE _IO('c', 101)
#define COVER_SIZE (64<<10)
int main(int argc, char **argv)
{
int fd;
unsigned long *cover, n, i;
/* A single fd descriptor allows coverage collection on a single
* thread.
*/
fd = open("/sys/kernel/debug/kcov", O_RDWR);
if (fd == -1)
perror("open"), exit(1);
/* Setup trace mode and trace size. */
if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE))
perror("ioctl"), exit(1);
/* Mmap buffer shared between kernel- and user-space. */
cover = (unsigned long*)mmap(NULL, COVER_SIZE * sizeof(unsigned long),
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if ((void*)cover == MAP_FAILED)
perror("mmap"), exit(1);
/* Enable coverage collection on the current thread. */
if (ioctl(fd, KCOV_ENABLE, 0))
perror("ioctl"), exit(1);
/* Reset coverage from the tail of the ioctl() call. */
__atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED);
/* That's the target syscal call. */
read(-1, NULL, 0);
/* Read number of PCs collected. */
n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED);
for (i = 0; i < n; i++)
printf("0x%lx\n", cover[i + 1]);
/* Disable coverage collection for the current thread. After this call
* coverage can be enabled for a different thread.
*/
if (ioctl(fd, KCOV_DISABLE, 0))
perror("ioctl"), exit(1);
/* Free resources. */
if (munmap(cover, COVER_SIZE * sizeof(unsigned long)))
perror("munmap"), exit(1);
if (close(fd))
perror("close"), exit(1);
return 0;
}
After piping through addr2line output of the program looks as follows:
SyS_read
fs/read_write.c:562
__fdget_pos
fs/file.c:774
__fget_light
fs/file.c:746
__fget_light
fs/file.c:750
__fget_light
fs/file.c:760
__fdget_pos
fs/file.c:784
SyS_read
fs/read_write.c:562
If a program needs to collect coverage from several threads (independently),
it needs to open /sys/kernel/debug/kcov in each thread separately.
The interface is fine-grained to allow efficient forking of test processes.
That is, a parent process opens /sys/kernel/debug/kcov, enables trace mode,
mmaps coverage buffer and then forks child processes in a loop. Child processes
only need to enable coverage (disable happens automatically on thread end).
RapidIO subsystem mport character device driver (rio_mport_cdev.c)
==================================================================
Version History:
----------------
1.0.0 - Initial driver release.
==================================================================
I. Overview
This device driver is the result of collaboration within the RapidIO.org
Software Task Group (STG) between Texas Instruments, Freescale,
Prodrive Technologies, Nokia Networks, BAE and IDT. Additional input was
received from other members of RapidIO.org. The objective was to create a
character mode driver interface which exposes the capabilities of RapidIO
devices directly to applications, in a manner that allows the numerous and
varied RapidIO implementations to interoperate.
This driver (MPORT_CDEV) provides access to basic RapidIO subsystem operations
for user-space applications. Most of RapidIO operations are supported through
'ioctl' system calls.
When loaded this device driver creates filesystem nodes named rio_mportX in /dev
directory for each registered RapidIO mport device. 'X' in the node name matches
to unique port ID assigned to each local mport device.
Using available set of ioctl commands user-space applications can perform
following RapidIO bus and subsystem operations:
- Reads and writes from/to configuration registers of mport devices
(RIO_MPORT_MAINT_READ_LOCAL/RIO_MPORT_MAINT_WRITE_LOCAL)
- Reads and writes from/to configuration registers of remote RapidIO devices.
This operations are defined as RapidIO Maintenance reads/writes in RIO spec.
(RIO_MPORT_MAINT_READ_REMOTE/RIO_MPORT_MAINT_WRITE_REMOTE)
- Set RapidIO Destination ID for mport devices (RIO_MPORT_MAINT_HDID_SET)
- Set RapidIO Component Tag for mport devices (RIO_MPORT_MAINT_COMPTAG_SET)
- Query logical index of mport devices (RIO_MPORT_MAINT_PORT_IDX_GET)
- Query capabilities and RapidIO link configuration of mport devices
(RIO_MPORT_GET_PROPERTIES)
- Enable/Disable reporting of RapidIO doorbell events to user-space applications
(RIO_ENABLE_DOORBELL_RANGE/RIO_DISABLE_DOORBELL_RANGE)
- Enable/Disable reporting of RIO port-write events to user-space applications
(RIO_ENABLE_PORTWRITE_RANGE/RIO_DISABLE_PORTWRITE_RANGE)
- Query/Control type of events reported through this driver: doorbells,
port-writes or both (RIO_SET_EVENT_MASK/RIO_GET_EVENT_MASK)
- Configure/Map mport's outbound requests window(s) for specific size,
RapidIO destination ID, hopcount and request type
(RIO_MAP_OUTBOUND/RIO_UNMAP_OUTBOUND)
- Configure/Map mport's inbound requests window(s) for specific size,
RapidIO base address and local memory base address
(RIO_MAP_INBOUND/RIO_UNMAP_INBOUND)
- Allocate/Free contiguous DMA coherent memory buffer for DMA data transfers
to/from remote RapidIO devices (RIO_ALLOC_DMA/RIO_FREE_DMA)
- Initiate DMA data transfers to/from remote RapidIO devices (RIO_TRANSFER).
Supports blocking, asynchronous and posted (a.k.a 'fire-and-forget') data
transfer modes.
- Check/Wait for completion of asynchronous DMA data transfer
(RIO_WAIT_FOR_ASYNC)
- Manage device objects supported by RapidIO subsystem (RIO_DEV_ADD/RIO_DEV_DEL).
This allows implementation of various RapidIO fabric enumeration algorithms
as user-space applications while using remaining functionality provided by
kernel RapidIO subsystem.
II. Hardware Compatibility
This device driver uses standard interfaces defined by kernel RapidIO subsystem
and therefore it can be used with any mport device driver registered by RapidIO
subsystem with limitations set by available mport implementation.
At this moment the most common limitation is availability of RapidIO-specific
DMA engine framework for specific mport device. Users should verify available
functionality of their platform when planning to use this driver:
- IDT Tsi721 PCIe-to-RapidIO bridge device and its mport device driver are fully
compatible with this driver.
- Freescale SoCs 'fsl_rio' mport driver does not have implementation for RapidIO
specific DMA engine support and therefore DMA data transfers mport_cdev driver
are not available.
III. Module parameters
- 'dbg_level' - This parameter allows to control amount of debug information
generated by this device driver. This parameter is formed by set of
This parameter can be changed bit masks that correspond to the specific
functional block.
For mask definitions see 'drivers/rapidio/devices/rio_mport_cdev.c'
This parameter can be changed dynamically.
Use CONFIG_RAPIDIO_DEBUG=y to enable debug output at the top level.
IV. Known problems
None.
V. User-space Applications and API
API library and applications that use this device driver are available from
RapidIO.org.
VI. TODO List
- Add support for sending/receiving "raw" RapidIO messaging packets.
- Add memory mapped DMA data transfers as an option when RapidIO-specific DMA
is not available.
......@@ -16,6 +16,15 @@ For inbound messages this driver uses destination ID matching to forward message
into the corresponding message queue. Messaging callbacks are implemented to be
fully compatible with RIONET driver (Ethernet over RapidIO messaging services).
1. Module parameters:
- 'dbg_level' - This parameter allows to control amount of debug information
generated by this device driver. This parameter is formed by set of
This parameter can be changed bit masks that correspond to the specific
functional block.
For mask definitions see 'drivers/rapidio/devices/tsi721.h'
This parameter can be changed dynamically.
Use CONFIG_RAPIDIO_DEBUG=y to enable debug output at the top level.
II. Known problems
None.
......
......@@ -365,6 +365,7 @@ LDFLAGS_MODULE =
CFLAGS_KERNEL =
AFLAGS_KERNEL =
CFLAGS_GCOV = -fprofile-arcs -ftest-coverage
CFLAGS_KCOV = -fsanitize-coverage=trace-pc
# Use USERINCLUDE when you must reference the UAPI directories only.
......@@ -411,7 +412,7 @@ export MAKE AWK GENKSYMS INSTALLKERNEL PERL PYTHON UTS_MACHINE
export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS
export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS
export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV CFLAGS_KASAN CFLAGS_UBSAN
export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV CFLAGS_KCOV CFLAGS_KASAN CFLAGS_UBSAN
export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE
export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL
......@@ -673,6 +674,14 @@ endif
endif
KBUILD_CFLAGS += $(stackp-flag)
ifdef CONFIG_KCOV
ifeq ($(call cc-option, $(CFLAGS_KCOV)),)
$(warning Cannot use CONFIG_KCOV: \
-fsanitize-coverage=trace-pc is not supported by compiler)
CFLAGS_KCOV =
endif
endif
ifeq ($(cc-name),clang)
KBUILD_CPPFLAGS += $(call cc-option,-Qunused-arguments,)
KBUILD_CPPFLAGS += $(call cc-option,-Wno-unknown-warning-option,)
......
......@@ -483,7 +483,13 @@ struct exception_table_entry
(pc) + (_fixup)->fixup.bits.nextinsn; \
})
#define ARCH_HAS_SORT_EXTABLE
#define ARCH_HAS_SEARCH_EXTABLE
#define ARCH_HAS_RELATIVE_EXTABLE
#define swap_ex_entry_fixup(a, b, tmp, delta) \
do { \
(a)->fixup.unit = (b)->fixup.unit; \
(b)->fixup.unit = (tmp).fixup.unit; \
} while (0)
#endif /* __ALPHA_UACCESS_H */
......@@ -4,6 +4,6 @@
ccflags-y := -Werror
obj-y := init.o fault.o extable.o
obj-y := init.o fault.o
obj-$(CONFIG_DISCONTIGMEM) += numa.o
/*
* linux/arch/alpha/mm/extable.c
*/
#include <linux/module.h>
#include <linux/sort.h>
#include <asm/uaccess.h>
static inline unsigned long ex_to_addr(const struct exception_table_entry *x)
{
return (unsigned long)&x->insn + x->insn;
}
static void swap_ex(void *a, void *b, int size)
{
struct exception_table_entry *ex_a = a, *ex_b = b;
unsigned long addr_a = ex_to_addr(ex_a), addr_b = ex_to_addr(ex_b);
unsigned int t = ex_a->fixup.unit;
ex_a->fixup.unit = ex_b->fixup.unit;
ex_b->fixup.unit = t;
ex_a->insn = (int)(addr_b - (unsigned long)&ex_a->insn);
ex_b->insn = (int)(addr_a - (unsigned long)&ex_b->insn);
}
/*
* The exception table needs to be sorted so that the binary
* search that we use to find entries in it works properly.
* This is used both for the kernel exception table and for
* the exception tables of modules that get loaded.
*/
static int cmp_ex(const void *a, const void *b)
{
const struct exception_table_entry *x = a, *y = b;
/* avoid overflow */
if (ex_to_addr(x) > ex_to_addr(y))
return 1;
if (ex_to_addr(x) < ex_to_addr(y))
return -1;
return 0;
}
void sort_extable(struct exception_table_entry *start,
struct exception_table_entry *finish)
{
sort(start, finish - start, sizeof(struct exception_table_entry),
cmp_ex, swap_ex);
}
#ifdef CONFIG_MODULES
/*
* Any entry referring to the module init will be at the beginning or
* the end.
*/
void trim_init_extable(struct module *m)
{
/*trim the beginning*/
while (m->num_exentries &&
within_module_init(ex_to_addr(&m->extable[0]), m)) {
m->extable++;
m->num_exentries--;
}
/*trim the end*/
while (m->num_exentries &&
within_module_init(ex_to_addr(&m->extable[m->num_exentries-1]),
m))
m->num_exentries--;
}
#endif /* CONFIG_MODULES */
const struct exception_table_entry *
search_extable(const struct exception_table_entry *first,
const struct exception_table_entry *last,
unsigned long value)
{
while (first <= last) {
const struct exception_table_entry *mid;
unsigned long mid_value;
mid = (last - first) / 2 + first;
mid_value = ex_to_addr(mid);
if (mid_value == value)
return mid;
else if (mid_value < value)
first = mid+1;
else
last = mid-1;
}
return NULL;
}
......@@ -341,13 +341,11 @@ extern unsigned long __strnlen_user (const char __user *, long);
__su_ret; \
})
/* Generic code can't deal with the location-relative format that we use for compactness. */
#define ARCH_HAS_SORT_EXTABLE
#define ARCH_HAS_SEARCH_EXTABLE
#define ARCH_HAS_RELATIVE_EXTABLE
struct exception_table_entry {
int addr; /* location-relative address of insn this fixup is for */
int cont; /* location-relative continuation addr.; if bit 2 is set, r9 is set to 0 */
int insn; /* location-relative address of insn this fixup is for */
int fixup; /* location-relative continuation addr.; if bit 2 is set, r9 is set to 0 */
};
extern void ia64_handle_exception (struct pt_regs *regs, const struct exception_table_entry *e);
......
......@@ -5,107 +5,12 @@
* David Mosberger-Tang <davidm@hpl.hp.com>
*/
#include <linux/sort.h>
#include <asm/uaccess.h>
#include <linux/module.h>
static int cmp_ex(const void *a, const void *b)
{
const struct exception_table_entry *l = a, *r = b;
u64 lip = (u64) &l->addr + l->addr;
u64 rip = (u64) &r->addr + r->addr;
/* avoid overflow */
if (lip > rip)
return 1;
if (lip < rip)
return -1;
return 0;
}
static void swap_ex(void *a, void *b, int size)
{
struct exception_table_entry *l = a, *r = b, tmp;
u64 delta = (u64) r - (u64) l;
tmp = *l;
l->addr = r->addr + delta;
l->cont = r->cont + delta;
r->addr = tmp.addr - delta;
r->cont = tmp.cont - delta;
}
/*
* Sort the exception table. It's usually already sorted, but there
* may be unordered entries due to multiple text sections (such as the
* .init text section). Note that the exception-table-entries contain
* location-relative addresses, which requires a bit of care during
* sorting to avoid overflows in the offset members (e.g., it would
* not be safe to make a temporary copy of an exception-table entry on
* the stack, because the stack may be more than 2GB away from the
* exception-table).
*/
void sort_extable (struct exception_table_entry *start,
struct exception_table_entry *finish)
{
sort(start, finish - start, sizeof(struct exception_table_entry),
cmp_ex, swap_ex);
}
static inline unsigned long ex_to_addr(const struct exception_table_entry *x)
{
return (unsigned long)&x->addr + x->addr;
}
#ifdef CONFIG_MODULES
/*
* Any entry referring to the module init will be at the beginning or
* the end.
*/
void trim_init_extable(struct module *m)
{
/*trim the beginning*/
while (m->num_exentries &&
within_module_init(ex_to_addr(&m->extable[0]), m)) {
m->extable++;
m->num_exentries--;
}
/*trim the end*/
while (m->num_exentries &&
within_module_init(ex_to_addr(&m->extable[m->num_exentries-1]),
m))
m->num_exentries--;
}
#endif /* CONFIG_MODULES */
const struct exception_table_entry *
search_extable (const struct exception_table_entry *first,
const struct exception_table_entry *last,
unsigned long ip)
{
const struct exception_table_entry *mid;
unsigned long mid_ip;
long diff;
while (first <= last) {
mid = &first[(last - first)/2];
mid_ip = (u64) &mid->addr + mid->addr;
diff = mid_ip - ip;
if (diff == 0)
return mid;
else if (diff < 0)
first = mid + 1;
else
last = mid - 1;
}
return NULL;
}
void
ia64_handle_exception (struct pt_regs *regs, const struct exception_table_entry *e)
{
long fix = (u64) &e->cont + e->cont;
long fix = (u64) &e->fixup + e->fixup;
regs->r8 = -EFAULT;
if (fix & 4)
......
......@@ -606,6 +606,12 @@ int fsl_rio_setup(struct platform_device *dev)
if (!port)
continue;
rc = rio_mport_initialize(port);
if (rc) {
kfree(port);
continue;
}
i = *port_index - 1;
port->index = (unsigned char)i;
......@@ -682,12 +688,6 @@ int fsl_rio_setup(struct platform_device *dev)
dev_info(&dev->dev, "RapidIO Common Transport System size: %d\n",
port->sys_size ? 65536 : 256);
if (rio_register_mport(port)) {
release_resource(&port->iores);
kfree(priv);
kfree(port);
continue;
}
if (port->host_deviceid >= 0)
out_be32(priv->regs_win + RIO_GCCSR, RIO_PORT_GEN_HOST |
RIO_PORT_GEN_MASTER | RIO_PORT_GEN_DISCOVERED);
......@@ -726,7 +726,14 @@ int fsl_rio_setup(struct platform_device *dev)
fsl_rio_inbound_mem_init(priv);
dbell->mport[i] = port;
pw->mport[i] = port;
if (rio_register_mport(port)) {
release_resource(&port->iores);
kfree(priv);
kfree(port);
continue;
}
active_ports++;
}
......
......@@ -97,6 +97,7 @@ struct fsl_rio_dbell {
};
struct fsl_rio_pw {
struct rio_mport *mport[MAX_PORT_NUM];
struct device *dev;
struct rio_pw_regs __iomem *pw_regs;
struct rio_port_write_msg port_write_msg;
......
......@@ -481,14 +481,14 @@ fsl_rio_port_write_handler(int irq, void *dev_instance)
static void fsl_pw_dpc(struct work_struct *work)
{
struct fsl_rio_pw *pw = container_of(work, struct fsl_rio_pw, pw_work);
u32 msg_buffer[RIO_PW_MSG_SIZE/sizeof(u32)];
union rio_pw_msg msg_buffer;
int i;
/*
* Process port-write messages
*/
while (kfifo_out_spinlocked(&pw->pw_fifo, (unsigned char *)msg_buffer,
while (kfifo_out_spinlocked(&pw->pw_fifo, (unsigned char *)&msg_buffer,
RIO_PW_MSG_SIZE, &pw->pw_fifo_lock)) {
/* Process one message */
#ifdef DEBUG_PW
{
u32 i;
......@@ -496,15 +496,19 @@ static void fsl_pw_dpc(struct work_struct *work)
for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32); i++) {
if ((i%4) == 0)
pr_debug("\n0x%02x: 0x%08x", i*4,
msg_buffer[i]);
msg_buffer.raw[i]);
else
pr_debug(" 0x%08x", msg_buffer[i]);
pr_debug(" 0x%08x", msg_buffer.raw[i]);
}
pr_debug("\n");
}
#endif
/* Pass the port-write message to RIO core for processing */
rio_inb_pwrite_handler((union rio_pw_msg *)msg_buffer);
for (i = 0; i < MAX_PORT_NUM; i++) {
if (pw->mport[i])
rio_inb_pwrite_handler(pw->mport[i],
&msg_buffer);
}
}
}
......
......@@ -79,18 +79,12 @@ struct exception_table_entry
int insn, fixup;
};
static inline unsigned long extable_insn(const struct exception_table_entry *x)
{
return (unsigned long)&x->insn + x->insn;
}
static inline unsigned long extable_fixup(const struct exception_table_entry *x)
{
return (unsigned long)&x->fixup + x->fixup;
}
#define ARCH_HAS_SORT_EXTABLE
#define ARCH_HAS_SEARCH_EXTABLE
#define ARCH_HAS_RELATIVE_EXTABLE
/**
* __copy_from_user: - Copy a block of data from user space, with less checking.
......
......@@ -3,7 +3,7 @@
#
obj-y := init.o fault.o extmem.o mmap.o vmem.o maccess.o
obj-y += page-states.o gup.o extable.o pageattr.o mem_detect.o
obj-y += page-states.o gup.o pageattr.o mem_detect.o
obj-y += pgtable.o pgalloc.o
obj-$(CONFIG_CMM) += cmm.o
......
#include <linux/module.h>
#include <linux/sort.h>
#include <asm/uaccess.h>
/*
* Search one exception table for an entry corresponding to the
* given instruction address, and return the address of the entry,
* or NULL if none is found.
* We use a binary search, and thus we assume that the table is
* already sorted.
*/
const struct exception_table_entry *
search_extable(const struct exception_table_entry *first,
const struct exception_table_entry *last,
unsigned long value)
{
const struct exception_table_entry *mid;
unsigned long addr;
while (first <= last) {
mid = ((last - first) >> 1) + first;
addr = extable_insn(mid);
if (addr < value)
first = mid + 1;
else if (addr > value)
last = mid - 1;
else
return mid;
}
return NULL;
}
/*
* The exception table needs to be sorted so that the binary
* search that we use to find entries in it works properly.
* This is used both for the kernel exception table and for
* the exception tables of modules that get loaded.
*
*/
static int cmp_ex(const void *a, const void *b)
{
const struct exception_table_entry *x = a, *y = b;
/* This compare is only valid after normalization. */
return x->insn - y->insn;
}
void sort_extable(struct exception_table_entry *start,
struct exception_table_entry *finish)
{
struct exception_table_entry *p;
int i;
/* Normalize entries to being relative to the start of the section */
for (p = start, i = 0; p < finish; p++, i += 8) {
p->insn += i;
p->fixup += i + 4;
}
sort(start, finish - start, sizeof(*start), cmp_ex, NULL);
/* Denormalize all entries */
for (p = start, i = 0; p < finish; p++, i += 8) {
p->insn -= i;
p->fixup -= i + 4;
}
}
#ifdef CONFIG_MODULES
/*
* If the exception table is sorted, any referring to the module init
* will be at the beginning or the end.
*/
void trim_init_extable(struct module *m)
{
/* Trim the beginning */
while (m->num_exentries &&
within_module_init(extable_insn(&m->extable[0]), m)) {
m->extable++;
m->num_exentries--;
}
/* Trim the end */
while (m->num_exentries &&
within_module_init(extable_insn(&m->extable[m->num_exentries-1]), m))
m->num_exentries--;
}
#endif /* CONFIG_MODULES */
......@@ -307,4 +307,11 @@ static inline int is_compat_task(void)
return test_thread_flag(TIF_32BIT);
}
static inline bool in_compat_syscall(void)
{
/* Vector 0x110 is LINUX_32BIT_SYSCALL_TRAP */
return pt_regs_trap_type(current_pt_regs()) == 0x110;
}
#define in_compat_syscall in_compat_syscall
#endif /* _ASM_SPARC64_COMPAT_H */
......@@ -3,6 +3,7 @@
#include <uapi/linux/audit.h>
#include <linux/kernel.h>
#include <linux/compat.h>
#include <linux/sched.h>
#include <asm/ptrace.h>
#include <asm/thread_info.h>
......@@ -128,7 +129,13 @@ static inline void syscall_set_arguments(struct task_struct *task,
static inline int syscall_get_arch(void)
{
return is_32bit_task() ? AUDIT_ARCH_SPARC : AUDIT_ARCH_SPARC64;
#if defined(CONFIG_SPARC64) && defined(CONFIG_COMPAT)
return in_compat_syscall() ? AUDIT_ARCH_SPARC : AUDIT_ARCH_SPARC64;
#elif defined(CONFIG_SPARC64)
return AUDIT_ARCH_SPARC64;
#else
return AUDIT_ARCH_SPARC;
#endif
}
#endif /* __ASM_SPARC_SYSCALL_H */
......@@ -133,7 +133,7 @@ void mconsole_proc(struct mc_request *req)
ptr += strlen("proc");
ptr = skip_spaces(ptr);
file = file_open_root(mnt->mnt_root, mnt, ptr, O_RDONLY);
file = file_open_root(mnt->mnt_root, mnt, ptr, O_RDONLY, 0);
if (IS_ERR(file)) {
mconsole_reply(req, "Failed to open file", 1, 0);
printk(KERN_ERR "open /proc/%s: %ld\n", ptr, PTR_ERR(file));
......
......@@ -28,6 +28,7 @@ config X86
select ARCH_HAS_ELF_RANDOMIZE
select ARCH_HAS_FAST_MULTIPLIER
select ARCH_HAS_GCOV_PROFILE_ALL
select ARCH_HAS_KCOV if X86_64
select ARCH_HAS_PMEM_API if X86_64
select ARCH_HAS_MMIO_FLUSH
select ARCH_HAS_SG_CHAIN
......
......@@ -12,6 +12,13 @@
KASAN_SANITIZE := n
OBJECT_FILES_NON_STANDARD := y
# Kernel does not boot with kcov instrumentation here.
# One of the problems observed was insertion of __sanitizer_cov_trace_pc()
# callback into middle of per-cpu data enabling code. Thus the callback observed
# inconsistent state and crashed. We are interested mostly in syscall coverage,
# so boot code is not interesting anyway.
KCOV_INSTRUMENT := n
# If you want to preset the SVGA mode, uncomment the next line and
# set SVGA_MODE to whatever number you want.
# Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode.
......
......@@ -19,6 +19,9 @@
KASAN_SANITIZE := n
OBJECT_FILES_NON_STANDARD := y
# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
KCOV_INSTRUMENT := n
targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \
vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4
......
......@@ -7,6 +7,9 @@ KASAN_SANITIZE := n
UBSAN_SANITIZE := n
OBJECT_FILES_NON_STANDARD := y
# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
KCOV_INSTRUMENT := n
VDSO64-$(CONFIG_X86_64) := y
VDSOX32-$(CONFIG_X86_X32_ABI) := y
VDSO32-$(CONFIG_X86_32) := y
......
......@@ -316,9 +316,10 @@ static inline bool is_x32_task(void)
return false;
}
static inline bool is_compat_task(void)
static inline bool in_compat_syscall(void)
{
return is_ia32_task() || is_x32_task();
}
#define in_compat_syscall in_compat_syscall /* override the generic impl */
#endif /* _ASM_X86_COMPAT_H */
......@@ -58,7 +58,7 @@ int ftrace_int3_handler(struct pt_regs *regs);
#define ARCH_TRACE_IGNORE_COMPAT_SYSCALLS 1
static inline bool arch_trace_is_compat_syscall(struct pt_regs *regs)
{
if (is_compat_task())
if (in_compat_syscall())
return true;
return false;
}
......
......@@ -105,9 +105,8 @@ static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, un
struct exception_table_entry {
int insn, fixup, handler;
};
/* This is not the generic standard exception_table_entry format */
#define ARCH_HAS_SORT_EXTABLE
#define ARCH_HAS_SEARCH_EXTABLE
#define ARCH_HAS_RELATIVE_EXTABLE
extern int fixup_exception(struct pt_regs *regs, int trapnr);
extern bool ex_has_fault_handler(unsigned long ip);
......
......@@ -25,6 +25,12 @@ OBJECT_FILES_NON_STANDARD_relocate_kernel_$(BITS).o := y
OBJECT_FILES_NON_STANDARD_mcount_$(BITS).o := y
OBJECT_FILES_NON_STANDARD_test_nx.o := y
# If instrumentation of this dir is enabled, boot hangs during first second.
# Probably could be more selective here, but note that files related to irqs,
# boot, dumpstack/stacktrace, etc are either non-interesting or can lead to
# non-deterministic coverage.
KCOV_INSTRUMENT := n
CFLAGS_irq.o := -I$(src)/../include/asm/trace
obj-y := process_$(BITS).o signal.o
......
......@@ -2,6 +2,10 @@
# Makefile for local APIC drivers and for the IO-APIC code
#
# Leads to non-deterministic coverage that is not a function of syscall inputs.
# In particualr, smp_apic_timer_interrupt() is called in random places.
KCOV_INSTRUMENT := n
obj-$(CONFIG_X86_LOCAL_APIC) += apic.o apic_noop.o ipi.o vector.o
obj-y += hw_nmi.o
......
......@@ -8,6 +8,10 @@ CFLAGS_REMOVE_common.o = -pg
CFLAGS_REMOVE_perf_event.o = -pg
endif
# If these files are instrumented, boot hangs during the first second.
KCOV_INSTRUMENT_common.o := n
KCOV_INSTRUMENT_perf_event.o := n
# Make sure load_percpu_segment has no stackprotector
nostackp := $(call cc-option, -fno-stack-protector)
CFLAGS_common.o := $(nostackp)
......
......@@ -478,7 +478,7 @@ void set_personality_ia32(bool x32)
if (current->mm)
current->mm->context.ia32_compat = TIF_X32;
current->personality &= ~READ_IMPLIES_EXEC;
/* is_compat_task() uses the presence of the x32
/* in_compat_syscall() uses the presence of the x32
syscall bit flag to determine compat status */
current_thread_info()->status &= ~TS_COMPAT;
} else {
......
......@@ -2,6 +2,9 @@
# Makefile for x86 specific library files.
#
# Produces uninteresting flaky coverage.
KCOV_INSTRUMENT_delay.o := n
inat_tables_script = $(srctree)/arch/x86/tools/gen-insn-attr-x86.awk
inat_tables_maps = $(srctree)/arch/x86/lib/x86-opcode-map.txt
quiet_cmd_inat_tables = GEN $@
......
# Kernel does not boot with instrumentation of tlb.c.
KCOV_INSTRUMENT_tlb.o := n
obj-y := init.o init_$(BITS).o fault.o ioremap.o extable.o pageattr.o mmap.o \
pat.o pgtable.o physaddr.o gup.o setup_nx.o
......
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/sort.h>
#include <asm/uaccess.h>
typedef bool (*ex_handler_t)(const struct exception_table_entry *,
struct pt_regs *, int);
static inline unsigned long
ex_insn_addr(const struct exception_table_entry *x)
{
return (unsigned long)&x->insn + x->insn;
}
static inline unsigned long
ex_fixup_addr(const struct exception_table_entry *x)
{
......@@ -110,104 +103,3 @@ int __init early_fixup_exception(unsigned long *ip)
*ip = new_ip;
return 1;
}
/*
* Search one exception table for an entry corresponding to the
* given instruction address, and return the address of the entry,
* or NULL if none is found.
* We use a binary search, and thus we assume that the table is
* already sorted.
*/
const struct exception_table_entry *
search_extable(const struct exception_table_entry *first,
const struct exception_table_entry *last,
unsigned long value)
{
while (first <= last) {
const struct exception_table_entry *mid;
unsigned long addr;
mid = ((last - first) >> 1) + first;
addr = ex_insn_addr(mid);
if (addr < value)
first = mid + 1;
else if (addr > value)
last = mid - 1;
else
return mid;
}
return NULL;
}
/*
* The exception table needs to be sorted so that the binary
* search that we use to find entries in it works properly.
* This is used both for the kernel exception table and for
* the exception tables of modules that get loaded.
*
*/
static int cmp_ex(const void *a, const void *b)
{
const struct exception_table_entry *x = a, *y = b;
/*
* This value will always end up fittin in an int, because on
* both i386 and x86-64 the kernel symbol-reachable address
* space is < 2 GiB.
*
* This compare is only valid after normalization.
*/
return x->insn - y->insn;
}
void sort_extable(struct exception_table_entry *start,
struct exception_table_entry *finish)
{
struct exception_table_entry *p;
int i;
/* Convert all entries to being relative to the start of the section */
i = 0;
for (p = start; p < finish; p++) {
p->insn += i;
i += 4;
p->fixup += i;
i += 4;
p->handler += i;
i += 4;
}
sort(start, finish - start, sizeof(struct exception_table_entry),
cmp_ex, NULL);
/* Denormalize all entries */
i = 0;
for (p = start; p < finish; p++) {
p->insn -= i;
i += 4;
p->fixup -= i;
i += 4;
p->handler -= i;
i += 4;
}
}
#ifdef CONFIG_MODULES
/*
* If the exception table is sorted, any referring to the module init
* will be at the beginning or the end.
*/
void trim_init_extable(struct module *m)
{
/*trim the beginning*/
while (m->num_exentries &&
within_module_init(ex_insn_addr(&m->extable[0]), m)) {
m->extable++;
m->num_exentries--;
}
/*trim the end*/
while (m->num_exentries &&
within_module_init(ex_insn_addr(&m->extable[m->num_exentries-1]), m))
m->num_exentries--;
}
#endif /* CONFIG_MODULES */
......@@ -9,6 +9,9 @@
KASAN_SANITIZE := n
OBJECT_FILES_NON_STANDARD := y
# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
KCOV_INSTRUMENT := n
always := realmode.bin realmode.relocs
wakeup-objs := wakeup_asm.o wakemain.o video-mode.o
......
......@@ -2,6 +2,7 @@
* Coherent per-device memory handling.
* Borrowed from i386
*/
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
......@@ -31,7 +32,10 @@ static bool dma_init_coherent_memory(
if (!size)
goto out;
mem_base = ioremap(phys_addr, size);
if (flags & DMA_MEMORY_MAP)
mem_base = memremap(phys_addr, size, MEMREMAP_WC);
else
mem_base = ioremap(phys_addr, size);
if (!mem_base)
goto out;
......@@ -54,8 +58,12 @@ static bool dma_init_coherent_memory(
out:
kfree(dma_mem);
if (mem_base)
iounmap(mem_base);
if (mem_base) {
if (flags & DMA_MEMORY_MAP)
memunmap(mem_base);
else
iounmap(mem_base);
}
return false;
}
......@@ -63,7 +71,11 @@ static void dma_release_coherent_memory(struct dma_coherent_mem *mem)
{
if (!mem)
return;
iounmap(mem->virt_base);
if (mem->flags & DMA_MEMORY_MAP)
memunmap(mem->virt_base);
else
iounmap(mem->virt_base);
kfree(mem->bitmap);
kfree(mem);
}
......@@ -175,7 +187,10 @@ int dma_alloc_from_coherent(struct device *dev, ssize_t size,
*/
*dma_handle = mem->device_base + (pageno << PAGE_SHIFT);
*ret = mem->virt_base + (pageno << PAGE_SHIFT);
memset(*ret, 0, size);
if (mem->flags & DMA_MEMORY_MAP)
memset(*ret, 0, size);
else
memset_io(*ret, 0, size);
spin_unlock_irqrestore(&mem->spinlock, flags);
return 1;
......
......@@ -1140,7 +1140,7 @@ ipmi_nmi(unsigned int val, struct pt_regs *regs)
the timer. So do so. */
pretimeout_since_last_heartbeat = 1;
if (atomic_inc_and_test(&preop_panic_excl))
panic(PFX "pre-timeout");
nmi_panic(regs, PFX "pre-timeout");
}
return NMI_HANDLED;
......
......@@ -221,7 +221,7 @@ struct inbound_phy_packet_event {
#ifdef CONFIG_COMPAT
static void __user *u64_to_uptr(u64 value)
{
if (is_compat_task())
if (in_compat_syscall())
return compat_ptr(value);
else
return (void __user *)(unsigned long)value;
......@@ -229,7 +229,7 @@ static void __user *u64_to_uptr(u64 value)
static u64 uptr_to_u64(void __user *ptr)
{
if (is_compat_task())
if (in_compat_syscall())
return ptr_to_compat(ptr);
else
return (u64)(unsigned long)ptr;
......
......@@ -231,7 +231,7 @@ sanity_check(struct efi_variable *var, efi_char16_t *name, efi_guid_t vendor,
static inline bool is_compat(void)
{
if (IS_ENABLED(CONFIG_COMPAT) && is_compat_task())
if (IS_ENABLED(CONFIG_COMPAT) && in_compat_syscall())
return true;
return false;
......
......@@ -25,6 +25,9 @@ KASAN_SANITIZE := n
UBSAN_SANITIZE := n
OBJECT_FILES_NON_STANDARD := y
# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
KCOV_INSTRUMENT := n
lib-y := efi-stub-helper.o
# include the stub's generic dependencies from lib/ when building for ARM/arm64
......
......@@ -107,7 +107,7 @@ static int kfd_open(struct inode *inode, struct file *filep)
if (iminor(inode) != 0)
return -ENODEV;
is_32bit_user_mode = is_compat_task();
is_32bit_user_mode = in_compat_syscall();
if (is_32bit_user_mode == true) {
dev_warn(kfd_device,
......
......@@ -311,7 +311,7 @@ static struct kfd_process *create_process(const struct task_struct *thread)
goto err_process_pqm_init;
/* init process apertures*/
process->is_32bit_user_mode = is_compat_task();
process->is_32bit_user_mode = in_compat_syscall();
if (kfd_init_apertures(process) != 0)
goto err_init_apretures;
......
......@@ -384,7 +384,7 @@ struct uhid_create_req_compat {
static int uhid_event_from_user(const char __user *buffer, size_t len,
struct uhid_event *event)
{
if (is_compat_task()) {
if (in_compat_syscall()) {
u32 type;
if (get_user(type, buffer))
......
......@@ -17,17 +17,7 @@
#ifdef CONFIG_COMPAT
/* Note to the author of this code: did it ever occur to
you why the ifdefs are needed? Think about it again. -AK */
#if defined(CONFIG_X86_64) || defined(CONFIG_TILE)
# define INPUT_COMPAT_TEST is_compat_task()
#elif defined(CONFIG_S390)
# define INPUT_COMPAT_TEST test_thread_flag(TIF_31BIT)
#elif defined(CONFIG_MIPS)
# define INPUT_COMPAT_TEST test_thread_flag(TIF_32BIT_ADDR)
#else
# define INPUT_COMPAT_TEST test_thread_flag(TIF_32BIT)
#endif
#define INPUT_COMPAT_TEST in_compat_syscall()
struct input_event_compat {
struct compat_timeval time;
......
......@@ -24,6 +24,7 @@
#include <linux/skbuff.h>
#include <linux/crc32.h>
#include <linux/ethtool.h>
#include <linux/reboot.h>
#define DRV_NAME "rionet"
#define DRV_VERSION "0.3"
......@@ -48,6 +49,8 @@ MODULE_LICENSE("GPL");
#define RIONET_TX_RING_SIZE CONFIG_RIONET_TX_SIZE
#define RIONET_RX_RING_SIZE CONFIG_RIONET_RX_SIZE
#define RIONET_MAX_NETS 8
#define RIONET_MSG_SIZE RIO_MAX_MSG_SIZE
#define RIONET_MAX_MTU (RIONET_MSG_SIZE - ETH_HLEN)
struct rionet_private {
struct rio_mport *mport;
......@@ -60,6 +63,7 @@ struct rionet_private {
spinlock_t lock;
spinlock_t tx_lock;
u32 msg_enable;
bool open;
};
struct rionet_peer {
......@@ -71,6 +75,7 @@ struct rionet_peer {
struct rionet_net {
struct net_device *ndev;
struct list_head peers;
spinlock_t lock; /* net info access lock */
struct rio_dev **active;
int nact; /* number of active peers */
};
......@@ -232,26 +237,32 @@ static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u
struct net_device *ndev = dev_id;
struct rionet_private *rnet = netdev_priv(ndev);
struct rionet_peer *peer;
unsigned char netid = rnet->mport->id;
if (netif_msg_intr(rnet))
printk(KERN_INFO "%s: doorbell sid %4.4x tid %4.4x info %4.4x",
DRV_NAME, sid, tid, info);
if (info == RIONET_DOORBELL_JOIN) {
if (!nets[rnet->mport->id].active[sid]) {
list_for_each_entry(peer,
&nets[rnet->mport->id].peers, node) {
if (!nets[netid].active[sid]) {
spin_lock(&nets[netid].lock);
list_for_each_entry(peer, &nets[netid].peers, node) {
if (peer->rdev->destid == sid) {
nets[rnet->mport->id].active[sid] =
peer->rdev;
nets[rnet->mport->id].nact++;
nets[netid].active[sid] = peer->rdev;
nets[netid].nact++;
}
}
spin_unlock(&nets[netid].lock);
rio_mport_send_doorbell(mport, sid,
RIONET_DOORBELL_JOIN);
}
} else if (info == RIONET_DOORBELL_LEAVE) {
nets[rnet->mport->id].active[sid] = NULL;
nets[rnet->mport->id].nact--;
spin_lock(&nets[netid].lock);
if (nets[netid].active[sid]) {
nets[netid].active[sid] = NULL;
nets[netid].nact--;
}
spin_unlock(&nets[netid].lock);
} else {
if (netif_msg_intr(rnet))
printk(KERN_WARNING "%s: unhandled doorbell\n",
......@@ -280,7 +291,7 @@ static void rionet_outb_msg_event(struct rio_mport *mport, void *dev_id, int mbo
struct net_device *ndev = dev_id;
struct rionet_private *rnet = netdev_priv(ndev);
spin_lock(&rnet->lock);
spin_lock(&rnet->tx_lock);
if (netif_msg_intr(rnet))
printk(KERN_INFO
......@@ -299,14 +310,16 @@ static void rionet_outb_msg_event(struct rio_mport *mport, void *dev_id, int mbo
if (rnet->tx_cnt < RIONET_TX_RING_SIZE)
netif_wake_queue(ndev);
spin_unlock(&rnet->lock);
spin_unlock(&rnet->tx_lock);
}
static int rionet_open(struct net_device *ndev)
{
int i, rc = 0;
struct rionet_peer *peer, *tmp;
struct rionet_peer *peer;
struct rionet_private *rnet = netdev_priv(ndev);
unsigned char netid = rnet->mport->id;
unsigned long flags;
if (netif_msg_ifup(rnet))
printk(KERN_INFO "%s: open\n", DRV_NAME);
......@@ -345,20 +358,13 @@ static int rionet_open(struct net_device *ndev)
netif_carrier_on(ndev);
netif_start_queue(ndev);
list_for_each_entry_safe(peer, tmp,
&nets[rnet->mport->id].peers, node) {
if (!(peer->res = rio_request_outb_dbell(peer->rdev,
RIONET_DOORBELL_JOIN,
RIONET_DOORBELL_LEAVE)))
{
printk(KERN_ERR "%s: error requesting doorbells\n",
DRV_NAME);
continue;
}
spin_lock_irqsave(&nets[netid].lock, flags);
list_for_each_entry(peer, &nets[netid].peers, node) {
/* Send a join message */
rio_send_doorbell(peer->rdev, RIONET_DOORBELL_JOIN);
}
spin_unlock_irqrestore(&nets[netid].lock, flags);
rnet->open = true;
out:
return rc;
......@@ -367,7 +373,9 @@ static int rionet_open(struct net_device *ndev)
static int rionet_close(struct net_device *ndev)
{
struct rionet_private *rnet = netdev_priv(ndev);
struct rionet_peer *peer, *tmp;
struct rionet_peer *peer;
unsigned char netid = rnet->mport->id;
unsigned long flags;
int i;
if (netif_msg_ifup(rnet))
......@@ -375,18 +383,21 @@ static int rionet_close(struct net_device *ndev)
netif_stop_queue(ndev);
netif_carrier_off(ndev);
rnet->open = false;
for (i = 0; i < RIONET_RX_RING_SIZE; i++)
kfree_skb(rnet->rx_skb[i]);
list_for_each_entry_safe(peer, tmp,
&nets[rnet->mport->id].peers, node) {
if (nets[rnet->mport->id].active[peer->rdev->destid]) {
spin_lock_irqsave(&nets[netid].lock, flags);
list_for_each_entry(peer, &nets[netid].peers, node) {
if (nets[netid].active[peer->rdev->destid]) {
rio_send_doorbell(peer->rdev, RIONET_DOORBELL_LEAVE);
nets[rnet->mport->id].active[peer->rdev->destid] = NULL;
nets[netid].active[peer->rdev->destid] = NULL;
}
rio_release_outb_dbell(peer->rdev, peer->res);
if (peer->res)
rio_release_outb_dbell(peer->rdev, peer->res);
}
spin_unlock_irqrestore(&nets[netid].lock, flags);
rio_release_inb_dbell(rnet->mport, RIONET_DOORBELL_JOIN,
RIONET_DOORBELL_LEAVE);
......@@ -400,22 +411,38 @@ static void rionet_remove_dev(struct device *dev, struct subsys_interface *sif)
{
struct rio_dev *rdev = to_rio_dev(dev);
unsigned char netid = rdev->net->hport->id;
struct rionet_peer *peer, *tmp;
struct rionet_peer *peer;
int state, found = 0;
unsigned long flags;
if (dev_rionet_capable(rdev)) {
list_for_each_entry_safe(peer, tmp, &nets[netid].peers, node) {
if (peer->rdev == rdev) {
if (nets[netid].active[rdev->destid]) {
nets[netid].active[rdev->destid] = NULL;
nets[netid].nact--;
if (!dev_rionet_capable(rdev))
return;
spin_lock_irqsave(&nets[netid].lock, flags);
list_for_each_entry(peer, &nets[netid].peers, node) {
if (peer->rdev == rdev) {
list_del(&peer->node);
if (nets[netid].active[rdev->destid]) {
state = atomic_read(&rdev->state);
if (state != RIO_DEVICE_GONE &&
state != RIO_DEVICE_INITIALIZING) {
rio_send_doorbell(rdev,
RIONET_DOORBELL_LEAVE);
}
list_del(&peer->node);
kfree(peer);
break;
nets[netid].active[rdev->destid] = NULL;
nets[netid].nact--;
}
found = 1;
break;
}
}
spin_unlock_irqrestore(&nets[netid].lock, flags);
if (found) {
if (peer->res)
rio_release_outb_dbell(rdev, peer->res);
kfree(peer);
}
}
static void rionet_get_drvinfo(struct net_device *ndev,
......@@ -443,6 +470,17 @@ static void rionet_set_msglevel(struct net_device *ndev, u32 value)
rnet->msg_enable = value;
}
static int rionet_change_mtu(struct net_device *ndev, int new_mtu)
{
if ((new_mtu < 68) || (new_mtu > RIONET_MAX_MTU)) {
printk(KERN_ERR "%s: Invalid MTU size %d\n",
ndev->name, new_mtu);
return -EINVAL;
}
ndev->mtu = new_mtu;
return 0;
}
static const struct ethtool_ops rionet_ethtool_ops = {
.get_drvinfo = rionet_get_drvinfo,
.get_msglevel = rionet_get_msglevel,
......@@ -454,7 +492,7 @@ static const struct net_device_ops rionet_netdev_ops = {
.ndo_open = rionet_open,
.ndo_stop = rionet_close,
.ndo_start_xmit = rionet_start_xmit,
.ndo_change_mtu = eth_change_mtu,
.ndo_change_mtu = rionet_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
};
......@@ -478,6 +516,7 @@ static int rionet_setup_netdev(struct rio_mport *mport, struct net_device *ndev)
/* Set up private area */
rnet = netdev_priv(ndev);
rnet->mport = mport;
rnet->open = false;
/* Set the default MAC address */
device_id = rio_local_get_device_id(mport);
......@@ -489,7 +528,7 @@ static int rionet_setup_netdev(struct rio_mport *mport, struct net_device *ndev)
ndev->dev_addr[5] = device_id & 0xff;
ndev->netdev_ops = &rionet_netdev_ops;
ndev->mtu = RIO_MAX_MSG_SIZE - 14;
ndev->mtu = RIONET_MAX_MTU;
ndev->features = NETIF_F_LLTX;
SET_NETDEV_DEV(ndev, &mport->dev);
ndev->ethtool_ops = &rionet_ethtool_ops;
......@@ -500,8 +539,11 @@ static int rionet_setup_netdev(struct rio_mport *mport, struct net_device *ndev)
rnet->msg_enable = RIONET_DEFAULT_MSGLEVEL;
rc = register_netdev(ndev);
if (rc != 0)
if (rc != 0) {
free_pages((unsigned long)nets[mport->id].active,
get_order(rionet_active_bytes));
goto out;
}
printk(KERN_INFO "%s: %s %s Version %s, MAC %pM, %s\n",
ndev->name,
......@@ -515,8 +557,6 @@ static int rionet_setup_netdev(struct rio_mport *mport, struct net_device *ndev)
return rc;
}
static unsigned long net_table[RIONET_MAX_NETS/sizeof(unsigned long) + 1];
static int rionet_add_dev(struct device *dev, struct subsys_interface *sif)
{
int rc = -ENODEV;
......@@ -525,19 +565,16 @@ static int rionet_add_dev(struct device *dev, struct subsys_interface *sif)
struct net_device *ndev = NULL;
struct rio_dev *rdev = to_rio_dev(dev);
unsigned char netid = rdev->net->hport->id;
int oldnet;
if (netid >= RIONET_MAX_NETS)
return rc;
oldnet = test_and_set_bit(netid, net_table);
/*
* If first time through this net, make sure local device is rionet
* capable and setup netdev (this step will be skipped in later probes
* on the same net).
*/
if (!oldnet) {
if (!nets[netid].ndev) {
rio_local_read_config_32(rdev->net->hport, RIO_SRC_OPS_CAR,
&lsrc_ops);
rio_local_read_config_32(rdev->net->hport, RIO_DST_OPS_CAR,
......@@ -555,30 +592,56 @@ static int rionet_add_dev(struct device *dev, struct subsys_interface *sif)
rc = -ENOMEM;
goto out;
}
nets[netid].ndev = ndev;
rc = rionet_setup_netdev(rdev->net->hport, ndev);
if (rc) {
printk(KERN_ERR "%s: failed to setup netdev (rc=%d)\n",
DRV_NAME, rc);
free_netdev(ndev);
goto out;
}
INIT_LIST_HEAD(&nets[netid].peers);
spin_lock_init(&nets[netid].lock);
nets[netid].nact = 0;
} else if (nets[netid].ndev == NULL)
goto out;
nets[netid].ndev = ndev;
}
/*
* If the remote device has mailbox/doorbell capabilities,
* add it to the peer list.
*/
if (dev_rionet_capable(rdev)) {
if (!(peer = kmalloc(sizeof(struct rionet_peer), GFP_KERNEL))) {
struct rionet_private *rnet;
unsigned long flags;
rnet = netdev_priv(nets[netid].ndev);
peer = kzalloc(sizeof(*peer), GFP_KERNEL);
if (!peer) {
rc = -ENOMEM;
goto out;
}
peer->rdev = rdev;
peer->res = rio_request_outb_dbell(peer->rdev,
RIONET_DOORBELL_JOIN,
RIONET_DOORBELL_LEAVE);
if (!peer->res) {
pr_err("%s: error requesting doorbells\n", DRV_NAME);
kfree(peer);
rc = -ENOMEM;
goto out;
}
spin_lock_irqsave(&nets[netid].lock, flags);
list_add_tail(&peer->node, &nets[netid].peers);
spin_unlock_irqrestore(&nets[netid].lock, flags);
pr_debug("%s: %s add peer %s\n",
DRV_NAME, __func__, rio_name(rdev));
/* If netdev is already opened, send join request to new peer */
if (rnet->open)
rio_send_doorbell(peer->rdev, RIONET_DOORBELL_JOIN);
}
return 0;
......@@ -586,6 +649,61 @@ static int rionet_add_dev(struct device *dev, struct subsys_interface *sif)
return rc;
}
static int rionet_shutdown(struct notifier_block *nb, unsigned long code,
void *unused)
{
struct rionet_peer *peer;
unsigned long flags;
int i;
pr_debug("%s: %s\n", DRV_NAME, __func__);
for (i = 0; i < RIONET_MAX_NETS; i++) {
if (!nets[i].ndev)
continue;
spin_lock_irqsave(&nets[i].lock, flags);
list_for_each_entry(peer, &nets[i].peers, node) {
if (nets[i].active[peer->rdev->destid]) {
rio_send_doorbell(peer->rdev,
RIONET_DOORBELL_LEAVE);
nets[i].active[peer->rdev->destid] = NULL;
}
}
spin_unlock_irqrestore(&nets[i].lock, flags);
}
return NOTIFY_DONE;
}
static void rionet_remove_mport(struct device *dev,
struct class_interface *class_intf)
{
struct rio_mport *mport = to_rio_mport(dev);
struct net_device *ndev;
int id = mport->id;
pr_debug("%s %s\n", __func__, mport->name);
WARN(nets[id].nact, "%s called when connected to %d peers\n",
__func__, nets[id].nact);
WARN(!nets[id].ndev, "%s called for mport without NDEV\n",
__func__);
if (nets[id].ndev) {
ndev = nets[id].ndev;
netif_stop_queue(ndev);
unregister_netdev(ndev);
free_pages((unsigned long)nets[id].active,
get_order(sizeof(void *) *
RIO_MAX_ROUTE_ENTRIES(mport->sys_size)));
nets[id].active = NULL;
free_netdev(ndev);
nets[id].ndev = NULL;
}
}
#ifdef MODULE
static struct rio_device_id rionet_id_table[] = {
{RIO_DEVICE(RIO_ANY_ID, RIO_ANY_ID)},
......@@ -602,40 +720,43 @@ static struct subsys_interface rionet_interface = {
.remove_dev = rionet_remove_dev,
};
static struct notifier_block rionet_notifier = {
.notifier_call = rionet_shutdown,
};
/* the rio_mport_interface is used to handle local mport devices */
static struct class_interface rio_mport_interface __refdata = {
.class = &rio_mport_class,
.add_dev = NULL,
.remove_dev = rionet_remove_mport,
};
static int __init rionet_init(void)
{
int ret;
ret = register_reboot_notifier(&rionet_notifier);
if (ret) {
pr_err("%s: failed to register reboot notifier (err=%d)\n",
DRV_NAME, ret);
return ret;
}
ret = class_interface_register(&rio_mport_interface);
if (ret) {
pr_err("%s: class_interface_register error: %d\n",
DRV_NAME, ret);
return ret;
}
return subsys_interface_register(&rionet_interface);
}
static void __exit rionet_exit(void)
{
struct rionet_private *rnet;
struct net_device *ndev;
struct rionet_peer *peer, *tmp;
int i;
for (i = 0; i < RIONET_MAX_NETS; i++) {
if (nets[i].ndev != NULL) {
ndev = nets[i].ndev;
rnet = netdev_priv(ndev);
unregister_netdev(ndev);
list_for_each_entry_safe(peer,
tmp, &nets[i].peers, node) {
list_del(&peer->node);
kfree(peer);
}
free_pages((unsigned long)nets[i].active,
get_order(sizeof(void *) *
RIO_MAX_ROUTE_ENTRIES(rnet->mport->sys_size)));
nets[i].active = NULL;
free_netdev(ndev);
}
}
unregister_reboot_notifier(&rionet_notifier);
subsys_interface_unregister(&rionet_interface);
class_interface_unregister(&rio_mport_interface);
}
late_initcall(rionet_init);
......
......@@ -67,6 +67,14 @@ config RAPIDIO_ENUM_BASIC
endchoice
config RAPIDIO_MPORT_CDEV
tristate "RapidIO /dev mport device driver"
depends on RAPIDIO
help
This option includes generic RapidIO mport device driver which
allows to user space applications to perform RapidIO-specific
operations through selected RapidIO mport.
menu "RapidIO Switch drivers"
depends on RAPIDIO
......
......@@ -5,3 +5,4 @@
obj-$(CONFIG_RAPIDIO_TSI721) += tsi721_mport.o
tsi721_mport-y := tsi721.o
tsi721_mport-$(CONFIG_RAPIDIO_DMA_ENGINE) += tsi721_dma.o
obj-$(CONFIG_RAPIDIO_MPORT_CDEV) += rio_mport_cdev.o
此差异已折叠。
此差异已折叠。
......@@ -21,6 +21,46 @@
#ifndef __TSI721_H
#define __TSI721_H
/* Debug output filtering masks */
enum {
DBG_NONE = 0,
DBG_INIT = BIT(0), /* driver init */
DBG_EXIT = BIT(1), /* driver exit */
DBG_MPORT = BIT(2), /* mport add/remove */
DBG_MAINT = BIT(3), /* maintenance ops messages */
DBG_DMA = BIT(4), /* DMA transfer messages */
DBG_DMAV = BIT(5), /* verbose DMA transfer messages */
DBG_IBW = BIT(6), /* inbound window */
DBG_EVENT = BIT(7), /* event handling messages */
DBG_OBW = BIT(8), /* outbound window messages */
DBG_DBELL = BIT(9), /* doorbell messages */
DBG_OMSG = BIT(10), /* doorbell messages */
DBG_IMSG = BIT(11), /* doorbell messages */
DBG_ALL = ~0,
};
#ifdef DEBUG
extern u32 dbg_level;
#define tsi_debug(level, dev, fmt, arg...) \
do { \
if (DBG_##level & dbg_level) \
dev_dbg(dev, "%s: " fmt "\n", __func__, ##arg); \
} while (0)
#else
#define tsi_debug(level, dev, fmt, arg...) \
no_printk(KERN_DEBUG "%s: " fmt "\n", __func__, ##arg)
#endif
#define tsi_info(dev, fmt, arg...) \
dev_info(dev, "%s: " fmt "\n", __func__, ##arg)
#define tsi_warn(dev, fmt, arg...) \
dev_warn(dev, "%s: WARNING " fmt "\n", __func__, ##arg)
#define tsi_err(dev, fmt, arg...) \
dev_err(dev, "%s: ERROR " fmt "\n", __func__, ##arg)
#define DRV_NAME "tsi721"
#define DEFAULT_HOPCOUNT 0xff
......@@ -674,7 +714,7 @@ struct tsi721_bdma_chan {
struct dma_chan dchan;
struct tsi721_tx_desc *tx_desc;
spinlock_t lock;
struct list_head active_list;
struct tsi721_tx_desc *active_tx;
struct list_head queue;
struct list_head free_list;
struct tasklet_struct tasklet;
......@@ -808,9 +848,38 @@ struct msix_irq {
};
#endif /* CONFIG_PCI_MSI */
struct tsi721_ib_win_mapping {
struct list_head node;
dma_addr_t lstart;
};
struct tsi721_ib_win {
u64 rstart;
u32 size;
dma_addr_t lstart;
bool active;
bool xlat;
struct list_head mappings;
};
struct tsi721_obw_bar {
u64 base;
u64 size;
u64 free;
};
struct tsi721_ob_win {
u64 base;
u32 size;
u16 destid;
u64 rstart;
bool active;
struct tsi721_obw_bar *pbar;
};
struct tsi721_device {
struct pci_dev *pdev;
struct rio_mport *mport;
struct rio_mport mport;
u32 flags;
void __iomem *regs;
#ifdef CONFIG_PCI_MSI
......@@ -843,11 +912,25 @@ struct tsi721_device {
/* Outbound Messaging */
int omsg_init[TSI721_OMSG_CHNUM];
struct tsi721_omsg_ring omsg_ring[TSI721_OMSG_CHNUM];
/* Inbound Mapping Windows */
struct tsi721_ib_win ib_win[TSI721_IBWIN_NUM];
int ibwin_cnt;
/* Outbound Mapping Windows */
struct tsi721_obw_bar p2r_bar[2];
struct tsi721_ob_win ob_win[TSI721_OBWIN_NUM];
int obwin_cnt;
};
#ifdef CONFIG_RAPIDIO_DMA_ENGINE
extern void tsi721_bdma_handler(struct tsi721_bdma_chan *bdma_chan);
extern int tsi721_register_dma(struct tsi721_device *priv);
extern void tsi721_unregister_dma(struct tsi721_device *priv);
extern void tsi721_dma_stop_all(struct tsi721_device *priv);
#else
#define tsi721_dma_stop_all(priv) do {} while (0)
#define tsi721_unregister_dma(priv) do {} while (0)
#endif
#endif
......@@ -131,6 +131,17 @@ static int rio_device_remove(struct device *dev)
return 0;
}
static void rio_device_shutdown(struct device *dev)
{
struct rio_dev *rdev = to_rio_dev(dev);
struct rio_driver *rdrv = rdev->driver;
dev_dbg(dev, "RIO: %s\n", __func__);
if (rdrv && rdrv->shutdown)
rdrv->shutdown(rdev);
}
/**
* rio_register_driver - register a new RIO driver
* @rdrv: the RIO driver structure to register
......@@ -229,6 +240,7 @@ struct bus_type rio_bus_type = {
.bus_groups = rio_bus_groups,
.probe = rio_device_probe,
.remove = rio_device_remove,
.shutdown = rio_device_shutdown,
.uevent = rio_uevent,
};
......
......@@ -39,6 +39,13 @@
static void rio_init_em(struct rio_dev *rdev);
struct rio_id_table {
u16 start; /* logical minimal id */
u32 max; /* max number of IDs in table */
spinlock_t lock;
unsigned long table[0];
};
static int next_destid = 0;
static int next_comptag = 1;
......@@ -62,7 +69,7 @@ static int rio_mport_phys_table[] = {
static u16 rio_destid_alloc(struct rio_net *net)
{
int destid;
struct rio_id_table *idtab = &net->destid_table;
struct rio_id_table *idtab = (struct rio_id_table *)net->enum_data;
spin_lock(&idtab->lock);
destid = find_first_zero_bit(idtab->table, idtab->max);
......@@ -88,7 +95,7 @@ static u16 rio_destid_alloc(struct rio_net *net)
static int rio_destid_reserve(struct rio_net *net, u16 destid)
{
int oldbit;
struct rio_id_table *idtab = &net->destid_table;
struct rio_id_table *idtab = (struct rio_id_table *)net->enum_data;
destid -= idtab->start;
spin_lock(&idtab->lock);
......@@ -106,7 +113,7 @@ static int rio_destid_reserve(struct rio_net *net, u16 destid)
*/
static void rio_destid_free(struct rio_net *net, u16 destid)
{
struct rio_id_table *idtab = &net->destid_table;
struct rio_id_table *idtab = (struct rio_id_table *)net->enum_data;
destid -= idtab->start;
spin_lock(&idtab->lock);
......@@ -121,7 +128,7 @@ static void rio_destid_free(struct rio_net *net, u16 destid)
static u16 rio_destid_first(struct rio_net *net)
{
int destid;
struct rio_id_table *idtab = &net->destid_table;
struct rio_id_table *idtab = (struct rio_id_table *)net->enum_data;
spin_lock(&idtab->lock);
destid = find_first_bit(idtab->table, idtab->max);
......@@ -141,7 +148,7 @@ static u16 rio_destid_first(struct rio_net *net)
static u16 rio_destid_next(struct rio_net *net, u16 from)
{
int destid;
struct rio_id_table *idtab = &net->destid_table;
struct rio_id_table *idtab = (struct rio_id_table *)net->enum_data;
spin_lock(&idtab->lock);
destid = find_next_bit(idtab->table, idtab->max, from);
......@@ -186,19 +193,6 @@ static void rio_set_device_id(struct rio_mport *port, u16 destid, u8 hopcount, u
RIO_SET_DID(port->sys_size, did));
}
/**
* rio_local_set_device_id - Set the base/extended device id for a port
* @port: RIO master port
* @did: Device ID value to be written
*
* Writes the base/extended device id from a device.
*/
static void rio_local_set_device_id(struct rio_mport *port, u16 did)
{
rio_local_write_config_32(port, RIO_DID_CSR, RIO_SET_DID(port->sys_size,
did));
}
/**
* rio_clear_locks- Release all host locks and signal enumeration complete
* @net: RIO network to run on
......@@ -449,9 +443,6 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
if (do_enum)
rio_route_clr_table(rdev, RIO_GLOBAL_TABLE, 0);
list_add_tail(&rswitch->node, &net->switches);
} else {
if (do_enum)
/*Enable Input Output Port (transmitter reviever)*/
......@@ -461,13 +452,9 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
rdev->comp_tag & RIO_CTAG_UDEVID);
}
rdev->dev.parent = &port->dev;
rdev->dev.parent = &net->dev;
rio_attach_device(rdev);
device_initialize(&rdev->dev);
rdev->dev.release = rio_release_dev;
rio_dev_get(rdev);
rdev->dma_mask = DMA_BIT_MASK(32);
rdev->dev.dma_mask = &rdev->dma_mask;
rdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
......@@ -480,6 +467,8 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
if (ret)
goto cleanup;
rio_dev_get(rdev);
return rdev;
cleanup:
......@@ -621,8 +610,6 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
rdev = rio_setup_device(net, port, RIO_ANY_DESTID(port->sys_size),
hopcount, 1);
if (rdev) {
/* Add device to the global and bus/net specific list. */
list_add_tail(&rdev->net_list, &net->devices);
rdev->prev = prev;
if (prev && rio_is_switch(prev))
prev->rswitch->nextdev[prev_port] = rdev;
......@@ -778,8 +765,6 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
/* Setup new RIO device */
if ((rdev = rio_setup_device(net, port, destid, hopcount, 0))) {
/* Add device to the global and bus/net specific list. */
list_add_tail(&rdev->net_list, &net->devices);
rdev->prev = prev;
if (prev && rio_is_switch(prev))
prev->rswitch->nextdev[prev_port] = rdev;
......@@ -864,50 +849,71 @@ static int rio_mport_is_active(struct rio_mport *port)
return result & RIO_PORT_N_ERR_STS_PORT_OK;
}
/**
* rio_alloc_net- Allocate and configure a new RIO network
* @port: Master port associated with the RIO network
static void rio_scan_release_net(struct rio_net *net)
{
pr_debug("RIO-SCAN: %s: net_%d\n", __func__, net->id);
kfree(net->enum_data);
}
static void rio_scan_release_dev(struct device *dev)
{
struct rio_net *net;
net = to_rio_net(dev);
pr_debug("RIO-SCAN: %s: net_%d\n", __func__, net->id);
kfree(net);
}
/*
* rio_scan_alloc_net - Allocate and configure a new RIO network
* @mport: Master port associated with the RIO network
* @do_enum: Enumeration/Discovery mode flag
* @start: logical minimal start id for new net
*
* Allocates a RIO network structure, initializes per-network
* list heads, and adds the associated master port to the
* network list of associated master ports. Returns a
* RIO network pointer on success or %NULL on failure.
* Allocates a new RIO network structure and initializes enumerator-specific
* part of it (if required).
* Returns a RIO network pointer on success or %NULL on failure.
*/
static struct rio_net *rio_alloc_net(struct rio_mport *port,
int do_enum, u16 start)
static struct rio_net *rio_scan_alloc_net(struct rio_mport *mport,
int do_enum, u16 start)
{
struct rio_net *net;
net = kzalloc(sizeof(struct rio_net), GFP_KERNEL);
net = rio_alloc_net(mport);
if (net && do_enum) {
net->destid_table.table = kcalloc(
BITS_TO_LONGS(RIO_MAX_ROUTE_ENTRIES(port->sys_size)),
sizeof(long),
GFP_KERNEL);
struct rio_id_table *idtab;
size_t size;
size = sizeof(struct rio_id_table) +
BITS_TO_LONGS(
RIO_MAX_ROUTE_ENTRIES(mport->sys_size)
) * sizeof(long);
idtab = kzalloc(size, GFP_KERNEL);
if (net->destid_table.table == NULL) {
if (idtab == NULL) {
pr_err("RIO: failed to allocate destID table\n");
kfree(net);
rio_free_net(net);
net = NULL;
} else {
net->destid_table.start = start;
net->destid_table.max =
RIO_MAX_ROUTE_ENTRIES(port->sys_size);
spin_lock_init(&net->destid_table.lock);
net->enum_data = idtab;
net->release = rio_scan_release_net;
idtab->start = start;
idtab->max = RIO_MAX_ROUTE_ENTRIES(mport->sys_size);
spin_lock_init(&idtab->lock);
}
}
if (net) {
INIT_LIST_HEAD(&net->node);
INIT_LIST_HEAD(&net->devices);
INIT_LIST_HEAD(&net->switches);
INIT_LIST_HEAD(&net->mports);
list_add_tail(&port->nnode, &net->mports);
net->hport = port;
net->id = port->id;
net->id = mport->id;
net->hport = mport;
dev_set_name(&net->dev, "rnet_%d", net->id);
net->dev.parent = &mport->dev;
net->dev.release = rio_scan_release_dev;
rio_add_net(net);
}
return net;
}
......@@ -967,17 +973,6 @@ static void rio_init_em(struct rio_dev *rdev)
}
}
/**
* rio_pw_enable - Enables/disables port-write handling by a master port
* @port: Master port associated with port-write handling
* @enable: 1=enable, 0=disable
*/
static void rio_pw_enable(struct rio_mport *port, int enable)
{
if (port->ops->pwenable)
port->ops->pwenable(port, enable);
}
/**
* rio_enum_mport- Start enumeration through a master port
* @mport: Master port to send transactions
......@@ -1016,7 +1011,7 @@ static int rio_enum_mport(struct rio_mport *mport, u32 flags)
/* If master port has an active link, allocate net and enum peers */
if (rio_mport_is_active(mport)) {
net = rio_alloc_net(mport, 1, 0);
net = rio_scan_alloc_net(mport, 1, 0);
if (!net) {
printk(KERN_ERR "RIO: failed to allocate new net\n");
rc = -ENOMEM;
......@@ -1133,7 +1128,7 @@ static int rio_disc_mport(struct rio_mport *mport, u32 flags)
enum_done:
pr_debug("RIO: ... enumeration done\n");
net = rio_alloc_net(mport, 0, 0);
net = rio_scan_alloc_net(mport, 0, 0);
if (!net) {
printk(KERN_ERR "RIO: Failed to allocate new net\n");
goto bail;
......
此差异已折叠。
......@@ -28,6 +28,7 @@ extern u32 rio_mport_get_efb(struct rio_mport *port, int local, u16 destid,
extern int rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid,
u8 hopcount);
extern int rio_create_sysfs_dev_files(struct rio_dev *rdev);
extern void rio_remove_sysfs_dev_files(struct rio_dev *rdev);
extern int rio_lock_device(struct rio_mport *port, u16 destid,
u8 hopcount, int wait_ms);
extern int rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount);
......@@ -38,7 +39,11 @@ extern int rio_route_get_entry(struct rio_dev *rdev, u16 table,
extern int rio_route_clr_table(struct rio_dev *rdev, u16 table, int lock);
extern int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock);
extern struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from);
extern struct rio_net *rio_alloc_net(struct rio_mport *mport);
extern int rio_add_net(struct rio_net *net);
extern void rio_free_net(struct rio_net *net);
extern int rio_add_device(struct rio_dev *rdev);
extern void rio_del_device(struct rio_dev *rdev, enum rio_device_state state);
extern int rio_enable_rx_tx_port(struct rio_mport *port, int local, u16 destid,
u8 hopcount, u8 port_num);
extern int rio_register_scan(int mport_id, struct rio_scan *scan_ops);
......
......@@ -657,7 +657,7 @@ static inline int ll_need_32bit_api(struct ll_sb_info *sbi)
#if BITS_PER_LONG == 32
return 1;
#elif defined(CONFIG_COMPAT)
return unlikely(is_compat_task() || (sbi->ll_flags & LL_SBI_32BIT_API));
return unlikely(in_compat_syscall() || (sbi->ll_flags & LL_SBI_32BIT_API));
#else
return unlikely(sbi->ll_flags & LL_SBI_32BIT_API);
#endif
......
......@@ -484,7 +484,7 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs)
static int die_nmi_called;
if (!hpwdt_nmi_decoding)
goto out;
return NMI_DONE;
spin_lock_irqsave(&rom_lock, rom_pl);
if (!die_nmi_called && !is_icru && !is_uefi)
......@@ -497,11 +497,11 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs)
if (!is_icru && !is_uefi) {
if (cmn_regs.u1.ral == 0) {
panic("An NMI occurred, "
"but unable to determine source.\n");
nmi_panic(regs, "An NMI occurred, but unable to determine source.\n");
return NMI_HANDLED;
}
}
panic("An NMI occurred. Depending on your system the reason "
nmi_panic(regs, "An NMI occurred. Depending on your system the reason "
"for the NMI is logged in any one of the following "
"resources:\n"
"1. Integrated Management Log (IML)\n"
......@@ -509,8 +509,7 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs)
"3. OA Forward Progress Log\n"
"4. iLO Event Log");
out:
return NMI_DONE;
return NMI_HANDLED;
}
#endif /* CONFIG_HPWDT_NMI_DECODING */
......
......@@ -32,6 +32,9 @@
#include <linux/pipe_fs_i.h>
#include <linux/oom.h>
#include <linux/compat.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/path.h>
#include <linux/timekeeping.h>
#include <asm/uaccess.h>
......@@ -649,6 +652,8 @@ void do_coredump(const siginfo_t *siginfo)
}
} else {
struct inode *inode;
int open_flags = O_CREAT | O_RDWR | O_NOFOLLOW |
O_LARGEFILE | O_EXCL;
if (cprm.limit < binfmt->min_coredump)
goto fail_unlock;
......@@ -687,10 +692,27 @@ void do_coredump(const siginfo_t *siginfo)
* what matters is that at least one of the two processes
* writes its coredump successfully, not which one.
*/
cprm.file = filp_open(cn.corename,
O_CREAT | 2 | O_NOFOLLOW |
O_LARGEFILE | O_EXCL,
0600);
if (need_suid_safe) {
/*
* Using user namespaces, normal user tasks can change
* their current->fs->root to point to arbitrary
* directories. Since the intention of the "only dump
* with a fully qualified path" rule is to control where
* coredumps may be placed using root privileges,
* current->fs->root must not be used. Instead, use the
* root directory of init_task.
*/
struct path root;
task_lock(&init_task);
get_fs_root(init_task.fs, &root);
task_unlock(&init_task);
cprm.file = file_open_root(root.dentry, root.mnt,
cn.corename, open_flags, 0600);
path_put(&root);
} else {
cprm.file = filp_open(cn.corename, open_flags, 0600);
}
if (IS_ERR(cprm.file))
goto fail_unlock;
......
......@@ -121,8 +121,46 @@ static unsigned int eventfd_poll(struct file *file, poll_table *wait)
u64 count;
poll_wait(file, &ctx->wqh, wait);
smp_rmb();
count = ctx->count;
/*
* All writes to ctx->count occur within ctx->wqh.lock. This read
* can be done outside ctx->wqh.lock because we know that poll_wait
* takes that lock (through add_wait_queue) if our caller will sleep.
*
* The read _can_ therefore seep into add_wait_queue's critical
* section, but cannot move above it! add_wait_queue's spin_lock acts
* as an acquire barrier and ensures that the read be ordered properly
* against the writes. The following CAN happen and is safe:
*
* poll write
* ----------------- ------------
* lock ctx->wqh.lock (in poll_wait)
* count = ctx->count
* __add_wait_queue
* unlock ctx->wqh.lock
* lock ctx->qwh.lock
* ctx->count += n
* if (waitqueue_active)
* wake_up_locked_poll
* unlock ctx->qwh.lock
* eventfd_poll returns 0
*
* but the following, which would miss a wakeup, cannot happen:
*
* poll write
* ----------------- ------------
* count = ctx->count (INVALID!)
* lock ctx->qwh.lock
* ctx->count += n
* **waitqueue_active is false**
* **no wake_up_locked_poll!**
* unlock ctx->qwh.lock
* lock ctx->wqh.lock (in poll_wait)
* __add_wait_queue
* unlock ctx->wqh.lock
* eventfd_poll returns 0
*/
count = READ_ONCE(ctx->count);
if (count > 0)
events |= POLLIN;
......
......@@ -285,7 +285,7 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
static inline int is_32bit_api(void)
{
#ifdef CONFIG_COMPAT
return is_compat_task();
return in_compat_syscall();
#else
return (BITS_PER_LONG == 32);
#endif
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册