Contact: Konrad Rzeszutek <ketuzsezr@darnok.org>
Description: The /sys/firmware/ibft/ethernetX directory will contain
files that expose the iSCSI Boot Firmware Table NIC data.
- This can this can the IP address, MAC, and gateway of the NIC.
+ Usually this contains the IP address, MAC, and gateway of the NIC.
PHONY += cleanmediadocs
cleanmediadocs:
- -@rm `find $(MEDIA_OBJ_DIR) -type l` $(GENFILES) $(OBJIMGFILES) 2>/dev/null
+ -@rm -f `find $(MEDIA_OBJ_DIR) -type l` $(GENFILES) $(OBJIMGFILES) 2>/dev/null
$(obj)/media_api.xml: $(GENFILES) FORCE
<para>Added compound control types and &VIDIOC-QUERY-EXT-CTRL;.
</para>
</listitem>
+ </orderedlist>
+ </section>
+
+ <section>
<title>V4L2 in Linux 3.18</title>
<orderedlist>
<listitem>
testing repository exists into which virtually all subsystem trees are
pulled on an almost daily basis:
http://git.kernel.org/?p=linux/kernel/git/next/linux-next.git
- http://linux.f-seidel.de/linux-next/pmwiki/
This way, the -next kernel gives a summary outlook onto what will be
expected to go into the mainline kernel at the next merge period.
14) Using Reported-by:, Tested-by:, Reviewed-by:, Suggested-by: and Fixes:
-If this patch fixes a problem reported by somebody else, consider adding a
-Reported-by: tag to credit the reporter for their contribution. Please
-note that this tag should not be added without the reporter's permission,
-especially if the problem was not reported in a public forum. That said,
-if we diligently credit our bug reporters, they will, hopefully, be
-inspired to help us again in the future.
+The Reported-by tag gives credit to people who find bugs and report them and it
+hopefully inspires them to help us again in the future. Please note that if
+the bug was reported in private, then ask for permission first before using the
+Reported-by tag.
A Tested-by: tag indicates that the patch has been successfully tested (in
some environment) by the person named. This tag informs maintainers that
http://www.kernel.org/pub/linux/kernel/next/
-Some information about linux-next has been gathered at:
-
- http://linux.f-seidel.de/linux-next/pmwiki/
-
Linux-next has become an integral part of the kernel development process;
all patches merged during a given merge window should really have found
their way into linux-next some time before the merge window opens.
http://kernelnewbies.org/
-Information about the linux-next tree gathers at:
-
- http://linux.f-seidel.de/linux-next/pmwiki/
-
And, of course, one should not forget http://kernel.org/, the definitive
location for kernel release information.
are supported on the device. Valid value for SMSC LAN91c111 are
1, 2 or 4. If it's omitted or invalid, the size would be 2 meaning
16-bit access only.
+- power-gpios: GPIO to control the PWRDWN pin
+- reset-gpios: GPIO to control the RESET pin
- clocks : the clock provider of SYS_MCLK
+- VDDA-supply : the regulator provider of VDDA
+
+- VDDIO-supply: the regulator provider of VDDIO
+
+Optional properties:
+
+- VDDD-supply : the regulator provider of VDDD
+
Example:
codec: sgtl5000@0a {
compatible = "fsl,sgtl5000";
reg = <0x0a>;
clocks = <&clks 150>;
+ VDDA-supply = <®_3p3v>;
+ VDDIO-supply = <®_3p3v>;
};
devicetree@vger.kernel.org
+ 3) The Documentation/ portion of the patch should come in the series before
+ the code implementing the binding.
+
II. For kernel maintainers
1) If you aren't comfortable reviewing a given binding, reply to it and ask
--- /dev/null
+* OMAP HDQ One wire bus master controller
+
+Required properties:
+- compatible : should be "ti,omap3-1w"
+- reg : Address and length of the register set for the device
+- interrupts : interrupt line.
+- ti,hwmods : "hdq1w"
+
+Example:
+
+- From omap3.dtsi
+ hdqw1w: 1w@480b2000 {
+ compatible = "ti,omap3-1w";
+ reg = <0x480b2000 0x1000>;
+ interrupts = <58>;
+ ti,hwmods = "hdq1w";
+ };
i8042.noloop [HW] Disable the AUX Loopback command while probing
for the AUX port
i8042.nomux [HW] Don't check presence of an active multiplexing
- controller. Default: true.
+ controller
i8042.nopnp [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX
controllers
i8042.notimeout [HW] Ignore timeout condition signalled by controller
.cdrom .chs .ignore_cable are additional options
See Documentation/ide/ide.txt.
+ ide-generic.probe-mask= [HW] (E)IDE subsystem
+ Format: <int>
+ Probe mask for legacy ISA IDE ports. Depending on
+ platform up to 6 ports are supported, enabled by
+ setting corresponding bits in the mask to 1. The
+ default value is 0x0, which has a special meaning.
+ On systems that have PCI, it triggers scanning the
+ PCI bus for the first and the second port, which
+ are then probed. On systems without PCI the value
+ of 0x0 enables probing the two first ports as if it
+ was 0x3.
+
ide-pci-generic.all-generic-ide [HW] (E)IDE subsystem
Claim all unknown PCI IDE storage controllers.
kmemleak= [KNL] Boot-time kmemleak enable/disable
Valid arguments: on, off
Default: on
+ Built with CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y,
+ the default is off.
kmemcheck= [X86] Boot-time kmemcheck enable/disable/one-shot mode
Valid arguments: 0, 1, 2
these actions are stored in an early log buffer. The size of this buffer
is configured via the CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE option.
+If CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF are enabled, the kmemleak is
+disabled by default. Passing "kmemleak=on" on the kernel command
+line enables the function.
+
Basic Algorithm
---------------
# List of programs to build
-hostprogs-y := disable-tsc-ctxt-sw-stress-test disable-tsc-on-off-stress-test disable-tsc-test
+hostprogs-$(CONFIG_X86) := disable-tsc-ctxt-sw-stress-test disable-tsc-on-off-stress-test disable-tsc-test
# Tell kbuild to always build the programs
always := $(hostprogs-y)
--- /dev/null
+# PTP 1588 clock support - User space test program
+#
+# Copyright (C) 2010 OMICRON electronics GmbH
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+CC = $(CROSS_COMPILE)gcc
+INC = -I$(KBUILD_OUTPUT)/usr/include
+CFLAGS = -Wall $(INC)
+LDLIBS = -lrt
+PROGS = testptp
+
+all: $(PROGS)
+
+testptp: testptp.o
+
+clean:
+ rm -f testptp.o
+
+distclean: clean
+ rm -f $(PROGS)
HOSTCFLAGS := -I$(objtree)/usr/include -std=gnu99
HOSTCFLAGS_vdso_standalone_test_x86.o := -fno-asynchronous-unwind-tables -fno-stack-protector
HOSTLOADLIBES_vdso_standalone_test_x86 := -nostdlib
+ifeq ($(CONFIG_X86_32),y)
+HOSTLOADLIBES_vdso_standalone_test_x86 += -lgcc_s
+endif
x86_syscall3(__NR_exit, code, 0, 0);
}
-void to_base10(char *lastdig, uint64_t n)
+void to_base10(char *lastdig, time_t n)
{
while (n) {
*lastdig = (n % 10) + '0';
/mnt/huge. Any files created on /mnt/huge uses huge pages. The uid and gid
options sets the owner and group of the root of the file system. By default
the uid and gid of the current process are taken. The mode option sets the
-mode of root of file system to value & 0777. This value is given in octal.
+mode of root of file system to value & 01777. This value is given in octal.
By default the value 0755 is picked. The size option sets the maximum value of
memory (huge pages) allowed for that filesystem (/mnt/huge). The size is
rounded down to HPAGE_SIZE. The option nr_inodes sets the maximum number of
F: drivers/block/cpqarray.*
HEWLETT-PACKARD SMART ARRAY RAID DRIVER (hpsa)
-M: "Stephen M. Cameron" <scameron@beardog.cce.hp.com>
+M: Don Brace <don.brace@pmcs.com>
L: iss_storagedev@hp.com
+L: storagedev@pmcs.com
+L: linux-scsi@vger.kernel.org
S: Supported
F: Documentation/scsi/hpsa.txt
F: drivers/scsi/hpsa*.[ch]
F: include/uapi/linux/cciss*.h
HEWLETT-PACKARD SMART CISS RAID DRIVER (cciss)
-M: Mike Miller <mike.miller@hp.com>
+M: Don Brace <don.brace@pmcs.com>
L: iss_storagedev@hp.com
+L: storagedev@pmcs.com
+L: linux-scsi@vger.kernel.org
S: Supported
F: Documentation/blockdev/cciss.txt
F: drivers/block/cciss*
F: drivers/crypto/nx/
IBM Power 842 compression accelerator
-M: Nathan Fontenot <nfont@linux.vnet.ibm.com>
+M: Dan Streetman <ddstreet@us.ibm.com>
S: Supported
F: drivers/crypto/nx/nx-842.c
F: include/linux/nx842.h
UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER
M: Vinayak Holikatti <vinholikatti@gmail.com>
-M: Santosh Y <santoshsy@gmail.com>
L: linux-scsi@vger.kernel.org
S: Supported
F: Documentation/scsi/ufs.txt
VERSION = 3
PATCHLEVEL = 18
SUBLEVEL = 0
-EXTRAVERSION = -rc2
-NAME = Shuffling Zombie Juror
+EXTRAVERSION = -rc3
+NAME = Diseased Newt
# *DOCUMENTATION*
# To see a list of typical targets execute "make help"
bank-width = <2>;
pinctrl-names = "default";
pinctrl-0 = <ðernet_pins>;
+ power-gpios = <&gpio3 22 GPIO_ACTIVE_HIGH>; /* gpio86 */
+ reset-gpios = <&gpio6 4 GPIO_ACTIVE_HIGH>; /* gpio164 */
gpmc,device-width = <2>;
gpmc,sync-clk-ps = <0>;
gpmc,cs-on-ns = <0>;
#define __NR_seccomp (__NR_SYSCALL_BASE+383)
#define __NR_getrandom (__NR_SYSCALL_BASE+384)
#define __NR_memfd_create (__NR_SYSCALL_BASE+385)
+#define __NR_bpf (__NR_SYSCALL_BASE+386)
/*
* The following SWIs are ARM private.
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <linux/compiler.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
* GCC 3.2.x: miscompiles NEW_AUX_ENT in fs/binfmt_elf.c
* (http://gcc.gnu.org/PR8896) and incorrect structure
* initialisation in fs/jffs2/erase.c
+ * GCC 4.8.0-4.8.2: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58854
+ * miscompiles find_get_entry(), and can result in EXT3 and EXT4
+ * filesystem corruption (possibly other FS too).
*/
+#ifdef __GNUC__
#if (__GNUC__ == 3 && __GNUC_MINOR__ < 3)
#error Your compiler is too buggy; it is known to miscompile kernels.
-#error Known good compilers: 3.3
+#error Known good compilers: 3.3, 4.x
+#endif
+#if GCC_VERSION >= 40800 && GCC_VERSION < 40803
+#error Your compiler is too buggy; it is known to miscompile kernels
+#error and result in filesystem corruption and oopses.
+#endif
#endif
int main(void)
CALL(sys_seccomp)
CALL(sys_getrandom)
/* 385 */ CALL(sys_memfd_create)
+ CALL(sys_bpf)
#ifndef syscalls_counted
.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
#define syscalls_counted
platform_device_register(&omap3_rom_rng_device);
}
-
- /* Only on some development boards */
- gpio_request_one(164, GPIOF_OUT_INIT_LOW, "smc91x reset");
}
static void __init omap3_tao3530_legacy_init(void)
* @associativity: variable to return the calculated associativity in
* @max_way_size: the maximum size in bytes for the cache ways
*/
-static void __init l2x0_cache_size_of_parse(const struct device_node *np,
+static int __init l2x0_cache_size_of_parse(const struct device_node *np,
u32 *aux_val, u32 *aux_mask,
u32 *associativity,
u32 max_way_size)
of_property_read_u32(np, "cache-line-size", &line_size);
if (!cache_size || !sets)
- return;
+ return -ENODEV;
/* All these l2 caches have the same line = block size actually */
if (!line_size) {
if (way_size > max_way_size) {
pr_err("L2C OF: set size %dKB is too large\n", way_size);
- return;
+ return -EINVAL;
}
pr_info("L2C OF: override cache size: %d bytes (%dKB)\n",
if (way_size_bits < 1 || way_size_bits > 6) {
pr_err("L2C OF: cache way size illegal: %dKB is not mapped\n",
way_size);
- return;
+ return -EINVAL;
}
mask |= L2C_AUX_CTRL_WAY_SIZE_MASK;
*aux_val &= ~mask;
*aux_val |= val;
*aux_mask &= ~mask;
+
+ return 0;
}
static void __init l2x0_of_parse(const struct device_node *np,
u32 dirty = 0;
u32 val = 0, mask = 0;
u32 assoc;
+ int ret;
of_property_read_u32(np, "arm,tag-latency", &tag);
if (tag) {
val |= (dirty - 1) << L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT;
}
- l2x0_cache_size_of_parse(np, aux_val, aux_mask, &assoc, SZ_256K);
+ ret = l2x0_cache_size_of_parse(np, aux_val, aux_mask, &assoc, SZ_256K);
+ if (ret)
+ return;
+
if (assoc > 8) {
pr_err("l2x0 of: cache setting yield too high associativity\n");
pr_err("l2x0 of: %d calculated, max 8\n", assoc);
u32 tag[3] = { 0, 0, 0 };
u32 filter[2] = { 0, 0 };
u32 assoc;
+ int ret;
of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag));
if (tag[0] && tag[1] && tag[2])
l2x0_base + L310_ADDR_FILTER_START);
}
- l2x0_cache_size_of_parse(np, aux_val, aux_mask, &assoc, SZ_512K);
+ ret = l2x0_cache_size_of_parse(np, aux_val, aux_mask, &assoc, SZ_512K);
+ if (ret)
+ return;
+
switch (assoc) {
case 16:
*aux_val &= ~L2X0_AUX_CTRL_ASSOC_MASK;
*aux_mask &= ~L2X0_AUX_CTRL_ASSOC_MASK;
break;
default:
- pr_err("PL310 OF: cache setting yield illegal associativity\n");
- pr_err("PL310 OF: %d calculated, only 8 and 16 legal\n", assoc);
+ pr_err("L2C-310 OF cache associativity %d invalid, only 8 or 16 permitted\n",
+ assoc);
break;
}
}
{
return dma_common_pages_remap(pages, size,
VM_ARM_DMA_CONSISTENT | VM_USERMAP, prot, caller);
- return NULL;
}
/*
{
unsigned long vaddr;
int idx, type;
+ struct page *page = pfn_to_page(pfn);
pagefault_disable();
+ if (!PageHighMem(page))
+ return page_address(page);
type = kmap_atomic_idx_push();
idx = type + KM_TYPE_NR * smp_processor_id();
#ifdef CONFIG_MODULES
" modules : 0x%08lx - 0x%08lx (%4ld MB)\n"
#endif
- " .text : 0x%p" " - 0x%p" " (%4d kB)\n"
- " .init : 0x%p" " - 0x%p" " (%4d kB)\n"
- " .data : 0x%p" " - 0x%p" " (%4d kB)\n"
- " .bss : 0x%p" " - 0x%p" " (%4d kB)\n",
+ " .text : 0x%p" " - 0x%p" " (%4td kB)\n"
+ " .init : 0x%p" " - 0x%p" " (%4td kB)\n"
+ " .data : 0x%p" " - 0x%p" " (%4td kB)\n"
+ " .bss : 0x%p" " - 0x%p" " (%4td kB)\n",
MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) +
(PAGE_SIZE)),
menu "Kernel features"
+config NR_CPUS
+ int
+ default "1"
+
config ADVANCED_OPTIONS
bool "Prompt for advanced kernel configuration options"
help
#endif /* __ASSEMBLY__ */
-#define __NR_syscalls 387
+#define __NR_syscalls 388
#endif /* _ASM_MICROBLAZE_UNISTD_H */
#define __NR_seccomp 384
#define __NR_getrandom 385
#define __NR_memfd_create 386
+#define __NR_bpf 387
#endif /* _UAPI_ASM_MICROBLAZE_UNISTD_H */
.long sys_seccomp
.long sys_getrandom /* 385 */
.long sys_memfd_create
+ .long sys_bpf
res = &hose->mem_resources[memno++];
break;
}
- if (res != NULL)
- of_pci_range_to_resource(&range, dev, res);
+ if (res != NULL) {
+ res->name = dev->full_name;
+ res->flags = range.flags;
+ res->start = range.cpu_addr;
+ res->end = range.cpu_addr + range.size - 1;
+ res->parent = res->child = res->sibling = NULL;
+ }
}
/* If there's an ISA hole and the pci_mem_offset is -not- matching
void flush_dcache_icache_hugepage(struct page *page);
-#if defined(CONFIG_PPC_MM_SLICES) || defined(CONFIG_PPC_SUBPAGE_PROT)
+#if defined(CONFIG_PPC_MM_SLICES)
int is_hugepage_only_range(struct mm_struct *mm, unsigned long addr,
unsigned long len);
#else
SYSCALL_SPU(seccomp)
SYSCALL_SPU(getrandom)
SYSCALL_SPU(memfd_create)
+SYSCALL_SPU(bpf)
#include <uapi/asm/unistd.h>
-#define __NR_syscalls 361
+#define __NR_syscalls 362
#define __NR__exit __NR_exit
#define NR_syscalls __NR_syscalls
#define __NR_seccomp 358
#define __NR_getrandom 359
#define __NR_memfd_create 360
+#define __NR_bpf 361
#endif /* _UAPI_ASM_POWERPC_UNISTD_H_ */
u64 vsid;
int psize, ssize;
- slb->esid = (ea & ESID_MASK) | SLB_ESID_V;
-
switch (REGION_ID(ea)) {
case USER_REGION_ID:
pr_devel("%s: 0x%llx -- USER_REGION_ID\n", __func__, ea);
vsid |= mmu_psize_defs[psize].sllp |
((ssize == MMU_SEGSIZE_1T) ? SLB_VSID_B_1T : 0);
+ slb->esid = (ea & (ssize == MMU_SEGSIZE_1T ? ESID_MASK_1T : ESID_MASK)) | SLB_ESID_V;
slb->vsid = vsid;
return 0;
cpu = smp_processor_id();
for (update = data; update; update = update->next) {
+ int new_nid = update->new_nid;
if (cpu != update->cpu)
continue;
- unmap_cpu_from_node(update->cpu);
- map_cpu_to_node(update->cpu, update->new_nid);
+ unmap_cpu_from_node(cpu);
+ map_cpu_to_node(cpu, new_nid);
+ set_cpu_numa_node(cpu, new_nid);
+ set_cpu_numa_mem(cpu, local_memory_node(new_nid));
vdso_getcpu_init();
}
slice_convert(mm, mask, psize);
}
+#ifdef CONFIG_HUGETLB_PAGE
/*
* is_hugepage_only_range() is used by generic code to verify whether
* a normal mmap mapping (non hugetlbfs) is valid on a given area.
#endif
return !slice_check_fit(mask, available);
}
-
+#endif
return 0;
}
-static int h_24x7_event_idx(struct perf_event *event)
-{
- return 0;
-}
-
static struct pmu h_24x7_pmu = {
.task_ctx_nr = perf_invalid_context,
.start = h_24x7_event_start,
.stop = h_24x7_event_stop,
.read = h_24x7_event_update,
- .event_idx = h_24x7_event_idx,
};
static int hv_24x7_init(void)
return 0;
}
-static int h_gpci_event_idx(struct perf_event *event)
-{
- return 0;
-}
-
static struct pmu h_gpci_pmu = {
.task_ctx_nr = perf_invalid_context,
.start = h_gpci_event_start,
.stop = h_gpci_event_stop,
.read = h_gpci_event_update,
- .event_idx = h_gpci_event_idx,
};
static int hv_gpci_init(void)
{
struct lpc_debugfs_entry *lpc = filp->private_data;
u32 data, pos, len, todo;
- __be32 bedata;
int rc;
if (!access_ok(VERIFY_WRITE, ubuf, count))
len = 2;
}
rc = opal_lpc_read(opal_lpc_chip_id, lpc->lpc_type, pos,
- &bedata, len);
+ &data, len);
if (rc)
return -ENXIO;
- data = be32_to_cpu(bedata);
switch(len) {
case 4:
rc = __put_user((u32)data, (u32 __user *)ubuf);
*/
#define OPAL_CALL(name, token) \
- _GLOBAL(name); \
+ _GLOBAL_TOC(name); \
mflr r0; \
std r0,16(r1); \
li r0,token; \
perf_pmu_enable(event->pmu);
}
-static int cpumsf_pmu_event_idx(struct perf_event *event)
-{
- return event->hw.idx;
-}
-
CPUMF_EVENT_ATTR(SF, SF_CYCLES_BASIC, PERF_EVENT_CPUM_SF);
CPUMF_EVENT_ATTR(SF, SF_CYCLES_BASIC_DIAG, PERF_EVENT_CPUM_SF_DIAG);
.stop = cpumsf_pmu_stop,
.read = cpumsf_pmu_read,
- .event_idx = cpumsf_pmu_event_idx,
.attr_groups = cpumsf_pmu_attr_groups,
};
};
static struct resource scif0_resources[] = {
- DEFINE_RES_MEM(0xfffffe80, 0x100),
+ DEFINE_RES_MEM(0xfffffe80, 0x10),
DEFINE_RES_IRQ(evt2irq(0x4e0)),
};
};
static struct resource scif1_resources[] = {
- DEFINE_RES_MEM(0xa4000150, 0x100),
+ DEFINE_RES_MEM(0xa4000150, 0x10),
DEFINE_RES_IRQ(evt2irq(0x900)),
};
};
static struct resource scif2_resources[] = {
- DEFINE_RES_MEM(0xa4000140, 0x100),
+ DEFINE_RES_MEM(0xa4000140, 0x10),
DEFINE_RES_IRQ(evt2irq(0x880)),
};
#define __NR_seccomp 346
#define __NR_getrandom 347
#define __NR_memfd_create 348
+#define __NR_bpf 349
-#define NR_syscalls 349
+#define NR_syscalls 350
/* Bitmask values returned from kern_features system call. */
#define KERN_FEATURE_MIXED_MODE_STACK 0x00000001
/*330*/ .long sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime
/*335*/ .long sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev
/*340*/ .long sys_ni_syscall, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr
-/*345*/ .long sys_renameat2, sys_seccomp, sys_getrandom, sys_memfd_create
+/*345*/ .long sys_renameat2, sys_seccomp, sys_getrandom, sys_memfd_create, sys_bpf
/*330*/ .word compat_sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, compat_sys_open_by_handle_at, compat_sys_clock_adjtime
.word sys_syncfs, compat_sys_sendmmsg, sys_setns, compat_sys_process_vm_readv, compat_sys_process_vm_writev
/*340*/ .word sys_kern_features, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr
- .word sys32_renameat2, sys_seccomp, sys_getrandom, sys_memfd_create
+ .word sys32_renameat2, sys_seccomp, sys_getrandom, sys_memfd_create, sys_bpf
#endif /* CONFIG_COMPAT */
/*330*/ .word sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime
.word sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev
/*340*/ .word sys_kern_features, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr
- .word sys_renameat2, sys_seccomp, sys_getrandom, sys_memfd_create
+ .word sys_renameat2, sys_seccomp, sys_getrandom, sys_memfd_create, sys_bpf
def_bool y
depends on KPROBES || PERF_EVENTS || UPROBES
+config PERF_EVENTS_INTEL_UNCORE
+ def_bool y
+ depends on PERF_EVENTS && SUP_SUP_INTEL && PCI
+
config OUTPUT_FORMAT
string
default "elf32-i386" if X86_32
* ourselves. To save a few cycles, we can check whether
* NT was set instead of doing an unconditional popfq.
*/
- testl $X86_EFLAGS_NT,EFLAGS(%rsp) /* saved EFLAGS match cpu */
+ testl $X86_EFLAGS_NT,EFLAGS-ARGOFFSET(%rsp)
jnz sysenter_fix_flags
sysenter_flags_fixed:
# ifdef CONFIG_CONTEXT_TRACKING
extern asmlinkage void ___preempt_schedule_context(void);
# define __preempt_schedule_context() asm ("call ___preempt_schedule_context")
+ extern asmlinkage void preempt_schedule_context(void);
# endif
#endif
/* Don't set up the ACPI SCI because it's already set up */
if (acpi_gbl_FADT.sci_interrupt == gsi)
- return gsi;
+ return mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC);
trigger = trigger == ACPI_EDGE_SENSITIVE ? 0 : 1;
polarity = polarity == ACPI_ACTIVE_HIGH ? 0 : 1;
int acpi_gsi_to_irq(u32 gsi, unsigned int *irqp)
{
- int irq = mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC | IOAPIC_MAP_CHECK);
+ int irq;
- if (irq >= 0) {
+ if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) {
+ *irqp = gsi;
+ } else {
+ irq = mp_map_gsi_to_irq(gsi,
+ IOAPIC_MAP_ALLOC | IOAPIC_MAP_CHECK);
+ if (irq < 0)
+ return -1;
*irqp = irq;
- return 0;
}
-
- return -1;
+ return 0;
}
EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
irq_modify_status(adev->irq, 0, IRQ_MOVE_PCNTXT);
irq_set_affinity(adev->irq, cpumask_of(adev->cpu));
- /* APB timer irqs are set up as mp_irqs, timer is edge type */
- __irq_set_handler(adev->irq, handle_edge_irq, 0, "edge");
}
/* Should be called with per cpu */
unsigned int value, queued;
int i, j, acked = 0;
unsigned long long tsc = 0, ntsc;
- long long max_loops = cpu_khz;
+ long long max_loops = cpu_khz ? cpu_khz : 1000000;
if (cpu_has_tsc)
rdtscll(tsc);
break;
}
if (queued) {
- if (cpu_has_tsc) {
+ if (cpu_has_tsc && cpu_khz) {
rdtscll(ntsc);
max_loops = (cpu_khz << 10) - (ntsc - tsc);
} else
endif
obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_p6.o perf_event_knc.o perf_event_p4.o
obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o
-obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_uncore.o perf_event_intel_uncore_snb.o
-obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_uncore_snbep.o perf_event_intel_uncore_nhmex.o
obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_rapl.o
+
+obj-$(CONFIG_PERF_EVENTS_INTEL_UNCORE) += perf_event_intel_uncore.o \
+ perf_event_intel_uncore_snb.o \
+ perf_event_intel_uncore_snbep.o \
+ perf_event_intel_uncore_nhmex.o
endif
{
#ifdef CONFIG_X86_F00F_BUG
/*
- * All current models of Pentium and Pentium with MMX technology CPUs
+ * All models of Pentium and Pentium with MMX technology CPUs
* have the F0 0F bug, which lets nonprivileged users lock up the
* system. Announce that the fault handler will be checking for it.
+ * The Quark is also family 5, but does not have the same bug.
*/
clear_cpu_bug(c, X86_BUG_F00F);
- if (!paravirt_enabled() && c->x86 == 5) {
+ if (!paravirt_enabled() && c->x86 == 5 && c->x86_model < 9) {
static int f00f_workaround_enabled;
set_cpu_bug(c, X86_BUG_F00F);
msr_fail:
printk(KERN_CONT "Broken PMU hardware detected, using software events only.\n");
- printk(boot_cpu_has(X86_FEATURE_HYPERVISOR) ? KERN_INFO : KERN_ERR
- "Failed to access perfctr msr (MSR %x is %Lx)\n", reg, val_new);
+ printk("%sFailed to access perfctr msr (MSR %x is %Lx)\n",
+ boot_cpu_has(X86_FEATURE_HYPERVISOR) ? KERN_INFO : KERN_ERR,
+ reg, val_new);
return false;
}
if (event->attr.type == PERF_TYPE_RAW)
event->hw.config |= event->attr.config & X86_RAW_EVENT_MASK;
- if (event->attr.sample_period && x86_pmu.limit_period) {
- if (x86_pmu.limit_period(event, event->attr.sample_period) >
- event->attr.sample_period)
- return -EINVAL;
- }
-
return x86_setup_perfctr(event);
}
if (left > x86_pmu.max_period)
left = x86_pmu.max_period;
- if (x86_pmu.limit_period)
- left = x86_pmu.limit_period(event, left);
-
per_cpu(pmc_prev_left[idx], smp_processor_id()) = left;
/*
struct x86_pmu_quirk *quirks;
int perfctr_second_write;
bool late_ack;
- unsigned (*limit_period)(struct perf_event *event, unsigned l);
/*
* sysfs attrs
EVENT_CONSTRAINT_END
};
-static struct event_constraint intel_bdw_event_constraints[] = {
- FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
- FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
- FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */
- INTEL_UEVENT_CONSTRAINT(0x148, 0x4), /* L1D_PEND_MISS.PENDING */
- INTEL_EVENT_CONSTRAINT(0xa3, 0x4), /* CYCLE_ACTIVITY.* */
- EVENT_CONSTRAINT_END
-};
-
static u64 intel_pmu_event_map(int hw_event)
{
return intel_perfmon_event_map[hw_event];
};
-static __initconst const u64 hsw_hw_cache_event_ids
- [PERF_COUNT_HW_CACHE_MAX]
- [PERF_COUNT_HW_CACHE_OP_MAX]
- [PERF_COUNT_HW_CACHE_RESULT_MAX] =
-{
- [ C(L1D ) ] = {
- [ C(OP_READ) ] = {
- [ C(RESULT_ACCESS) ] = 0x81d0, /* MEM_UOPS_RETIRED.ALL_LOADS */
- [ C(RESULT_MISS) ] = 0x151, /* L1D.REPLACEMENT */
- },
- [ C(OP_WRITE) ] = {
- [ C(RESULT_ACCESS) ] = 0x82d0, /* MEM_UOPS_RETIRED.ALL_STORES */
- [ C(RESULT_MISS) ] = 0x0,
- },
- [ C(OP_PREFETCH) ] = {
- [ C(RESULT_ACCESS) ] = 0x0,
- [ C(RESULT_MISS) ] = 0x0,
- },
- },
- [ C(L1I ) ] = {
- [ C(OP_READ) ] = {
- [ C(RESULT_ACCESS) ] = 0x0,
- [ C(RESULT_MISS) ] = 0x280, /* ICACHE.MISSES */
- },
- [ C(OP_WRITE) ] = {
- [ C(RESULT_ACCESS) ] = -1,
- [ C(RESULT_MISS) ] = -1,
- },
- [ C(OP_PREFETCH) ] = {
- [ C(RESULT_ACCESS) ] = 0x0,
- [ C(RESULT_MISS) ] = 0x0,
- },
- },
- [ C(LL ) ] = {
- [ C(OP_READ) ] = {
- /* OFFCORE_RESPONSE:ALL_DATA_RD|ALL_CODE_RD */
- [ C(RESULT_ACCESS) ] = 0x1b7,
- /* OFFCORE_RESPONSE:ALL_DATA_RD|ALL_CODE_RD|SUPPLIER_NONE|
- L3_MISS|ANY_SNOOP */
- [ C(RESULT_MISS) ] = 0x1b7,
- },
- [ C(OP_WRITE) ] = {
- [ C(RESULT_ACCESS) ] = 0x1b7, /* OFFCORE_RESPONSE:ALL_RFO */
- /* OFFCORE_RESPONSE:ALL_RFO|SUPPLIER_NONE|L3_MISS|ANY_SNOOP */
- [ C(RESULT_MISS) ] = 0x1b7,
- },
- [ C(OP_PREFETCH) ] = {
- [ C(RESULT_ACCESS) ] = 0x0,
- [ C(RESULT_MISS) ] = 0x0,
- },
- },
- [ C(DTLB) ] = {
- [ C(OP_READ) ] = {
- [ C(RESULT_ACCESS) ] = 0x81d0, /* MEM_UOPS_RETIRED.ALL_LOADS */
- [ C(RESULT_MISS) ] = 0x108, /* DTLB_LOAD_MISSES.MISS_CAUSES_A_WALK */
- },
- [ C(OP_WRITE) ] = {
- [ C(RESULT_ACCESS) ] = 0x82d0, /* MEM_UOPS_RETIRED.ALL_STORES */
- [ C(RESULT_MISS) ] = 0x149, /* DTLB_STORE_MISSES.MISS_CAUSES_A_WALK */
- },
- [ C(OP_PREFETCH) ] = {
- [ C(RESULT_ACCESS) ] = 0x0,
- [ C(RESULT_MISS) ] = 0x0,
- },
- },
- [ C(ITLB) ] = {
- [ C(OP_READ) ] = {
- [ C(RESULT_ACCESS) ] = 0x6085, /* ITLB_MISSES.STLB_HIT */
- [ C(RESULT_MISS) ] = 0x185, /* ITLB_MISSES.MISS_CAUSES_A_WALK */
- },
- [ C(OP_WRITE) ] = {
- [ C(RESULT_ACCESS) ] = -1,
- [ C(RESULT_MISS) ] = -1,
- },
- [ C(OP_PREFETCH) ] = {
- [ C(RESULT_ACCESS) ] = -1,
- [ C(RESULT_MISS) ] = -1,
- },
- },
- [ C(BPU ) ] = {
- [ C(OP_READ) ] = {
- [ C(RESULT_ACCESS) ] = 0xc4, /* BR_INST_RETIRED.ALL_BRANCHES */
- [ C(RESULT_MISS) ] = 0xc5, /* BR_MISP_RETIRED.ALL_BRANCHES */
- },
- [ C(OP_WRITE) ] = {
- [ C(RESULT_ACCESS) ] = -1,
- [ C(RESULT_MISS) ] = -1,
- },
- [ C(OP_PREFETCH) ] = {
- [ C(RESULT_ACCESS) ] = -1,
- [ C(RESULT_MISS) ] = -1,
- },
- },
-};
-
-static __initconst const u64 hsw_hw_cache_extra_regs
- [PERF_COUNT_HW_CACHE_MAX]
- [PERF_COUNT_HW_CACHE_OP_MAX]
- [PERF_COUNT_HW_CACHE_RESULT_MAX] =
-{
- [ C(LL ) ] = {
- [ C(OP_READ) ] = {
- /* OFFCORE_RESPONSE:ALL_DATA_RD|ALL_CODE_RD */
- [ C(RESULT_ACCESS) ] = 0x2d5,
- /* OFFCORE_RESPONSE:ALL_DATA_RD|ALL_CODE_RD|SUPPLIER_NONE|
- L3_MISS|ANY_SNOOP */
- [ C(RESULT_MISS) ] = 0x3fbc0202d5ull,
- },
- [ C(OP_WRITE) ] = {
- [ C(RESULT_ACCESS) ] = 0x122, /* OFFCORE_RESPONSE:ALL_RFO */
- /* OFFCORE_RESPONSE:ALL_RFO|SUPPLIER_NONE|L3_MISS|ANY_SNOOP */
- [ C(RESULT_MISS) ] = 0x3fbc020122ull,
- },
- [ C(OP_PREFETCH) ] = {
- [ C(RESULT_ACCESS) ] = 0x0,
- [ C(RESULT_MISS) ] = 0x0,
- },
- },
-};
-
static __initconst const u64 westmere_hw_cache_event_ids
[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
return c;
}
-/*
- * Broadwell:
- * The INST_RETIRED.ALL period always needs to have lowest
- * 6bits cleared (BDM57). It shall not use a period smaller
- * than 100 (BDM11). We combine the two to enforce
- * a min-period of 128.
- */
-static unsigned bdw_limit_period(struct perf_event *event, unsigned left)
-{
- if ((event->hw.config & INTEL_ARCH_EVENT_MASK) ==
- X86_CONFIG(.event=0xc0, .umask=0x01)) {
- if (left < 128)
- left = 128;
- left &= ~0x3fu;
- }
- return left;
-}
-
PMU_FORMAT_ATTR(event, "config:0-7" );
PMU_FORMAT_ATTR(umask, "config:8-15" );
PMU_FORMAT_ATTR(edge, "config:18" );
case 69: /* 22nm Haswell ULT */
case 70: /* 22nm Haswell + GT3e (Intel Iris Pro graphics) */
x86_pmu.late_ack = true;
- memcpy(hw_cache_event_ids, hsw_hw_cache_event_ids, sizeof(hw_cache_event_ids));
- memcpy(hw_cache_extra_regs, hsw_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
+ memcpy(hw_cache_event_ids, snb_hw_cache_event_ids, sizeof(hw_cache_event_ids));
+ memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
intel_pmu_lbr_init_snb();
pr_cont("Haswell events, ");
break;
- case 61: /* 14nm Broadwell Core-M */
- x86_pmu.late_ack = true;
- memcpy(hw_cache_event_ids, hsw_hw_cache_event_ids, sizeof(hw_cache_event_ids));
- memcpy(hw_cache_extra_regs, hsw_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
-
- intel_pmu_lbr_init_snb();
-
- x86_pmu.event_constraints = intel_bdw_event_constraints;
- x86_pmu.pebs_constraints = intel_hsw_pebs_event_constraints;
- x86_pmu.extra_regs = intel_snbep_extra_regs;
- x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
- /* all extra regs are per-cpu when HT is on */
- x86_pmu.er_flags |= ERF_HAS_RSP_1;
- x86_pmu.er_flags |= ERF_NO_HT_SHARING;
-
- x86_pmu.hw_config = hsw_hw_config;
- x86_pmu.get_event_constraints = hsw_get_event_constraints;
- x86_pmu.cpu_events = hsw_events_attrs;
- x86_pmu.limit_period = bdw_limit_period;
- pr_cont("Broadwell events, ");
- break;
-
default:
switch (x86_pmu.version) {
case 1:
sysenter_audit:
testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
jnz syscall_trace_entry
- addl $4,%esp
- CFI_ADJUST_CFA_OFFSET -4
- movl %esi,4(%esp) /* 5th arg: 4th syscall arg */
- movl %edx,(%esp) /* 4th arg: 3rd syscall arg */
- /* %ecx already in %ecx 3rd arg: 2nd syscall arg */
- movl %ebx,%edx /* 2nd arg: 1st syscall arg */
- /* %eax already in %eax 1st arg: syscall number */
+ /* movl PT_EAX(%esp), %eax already set, syscall number: 1st arg to audit */
+ movl PT_EBX(%esp), %edx /* ebx/a0: 2nd arg to audit */
+ /* movl PT_ECX(%esp), %ecx already set, a1: 3nd arg to audit */
+ pushl_cfi PT_ESI(%esp) /* a3: 5th arg */
+ pushl_cfi PT_EDX+4(%esp) /* a2: 4th arg */
call __audit_syscall_entry
- pushl_cfi %ebx
+ popl_cfi %ecx /* get that remapped edx off the stack */
+ popl_cfi %ecx /* get that remapped esi off the stack */
movl PT_EAX(%esp),%eax /* reload syscall number */
jmp sysenter_do_call
{
disable_irq_nosync(irq);
io_apic_irqs &= ~(1<<irq);
- irq_set_chip_and_handler_name(irq, &i8259A_chip, handle_level_irq,
- i8259A_chip.name);
+ irq_set_chip_and_handler(irq, &i8259A_chip, handle_level_irq);
enable_irq(irq);
}
void __init init_ISA_irqs(void)
{
struct irq_chip *chip = legacy_pic->chip;
- const char *name = chip->name;
int i;
#if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC)
legacy_pic->init(0);
for (i = 0; i < nr_legacy_irqs(); i++)
- irq_set_chip_and_handler_name(i, chip, handle_level_irq, name);
+ irq_set_chip_and_handler(i, chip, handle_level_irq);
}
void __init init_IRQ(void)
setup_real_mode();
memblock_set_current_limit(get_max_mapped());
- dma_contiguous_reserve(max_pfn_mapped << PAGE_SHIFT);
/*
* NOTE: On x86-32, only from this point on, fixmaps are ready for use.
early_acpi_boot_init();
initmem_init();
+ dma_contiguous_reserve(max_pfn_mapped << PAGE_SHIFT);
/*
* Reserve memory for crash kernel after SRAT is parsed so that it
DEFINE_PER_CPU_SHARED_ALIGNED(struct cpuinfo_x86, cpu_info);
EXPORT_PER_CPU_SYMBOL(cpu_info);
-static DEFINE_PER_CPU(struct completion, die_complete);
-
atomic_t init_deasserted;
/*
fixup_irqs();
}
+static DEFINE_PER_CPU(struct completion, die_complete);
+
int native_cpu_disable(void)
{
int ret;
x86_init.timers.tsc_pre_init();
- if (!cpu_has_tsc)
+ if (!cpu_has_tsc) {
+ setup_clear_cpu_cap(X86_FEATURE_TSC_DEADLINE_TIMER);
return;
+ }
tsc_khz = x86_platform.calibrate_tsc();
cpu_khz = tsc_khz;
if (!tsc_khz) {
mark_tsc_unstable("could not calculate TSC khz");
+ setup_clear_cpu_cap(X86_FEATURE_TSC_DEADLINE_TIMER);
return;
}
case 4:
ctxt->_eip = (u32)dst;
break;
+#ifdef CONFIG_X86_64
case 8:
if ((cs_l && is_noncanonical_address(dst)) ||
- (!cs_l && (dst & ~(u32)-1)))
+ (!cs_l && (dst >> 32) != 0))
return emulate_gp(ctxt, 0);
ctxt->_eip = dst;
break;
+#endif
default:
WARN(1, "unsupported eip assignment size\n");
}
static int __linearize(struct x86_emulate_ctxt *ctxt,
struct segmented_address addr,
- unsigned size, bool write, bool fetch,
+ unsigned *max_size, unsigned size,
+ bool write, bool fetch,
ulong *linear)
{
struct desc_struct desc;
unsigned cpl;
la = seg_base(ctxt, addr.seg) + addr.ea;
+ *max_size = 0;
switch (ctxt->mode) {
case X86EMUL_MODE_PROT64:
if (((signed long)la << 16) >> 16 != la)
return emulate_gp(ctxt, 0);
+
+ *max_size = min_t(u64, ~0u, (1ull << 48) - la);
+ if (size > *max_size)
+ goto bad;
break;
default:
usable = ctxt->ops->get_segment(ctxt, &sel, &desc, NULL,
if ((ctxt->mode == X86EMUL_MODE_REAL) && !fetch &&
(ctxt->d & NoBigReal)) {
/* la is between zero and 0xffff */
- if (la > 0xffff || (u32)(la + size - 1) > 0xffff)
+ if (la > 0xffff)
goto bad;
+ *max_size = 0x10000 - la;
} else if ((desc.type & 8) || !(desc.type & 4)) {
/* expand-up segment */
- if (addr.ea > lim || (u32)(addr.ea + size - 1) > lim)
+ if (addr.ea > lim)
goto bad;
+ *max_size = min_t(u64, ~0u, (u64)lim + 1 - addr.ea);
} else {
/* expand-down segment */
- if (addr.ea <= lim || (u32)(addr.ea + size - 1) <= lim)
+ if (addr.ea <= lim)
goto bad;
lim = desc.d ? 0xffffffff : 0xffff;
- if (addr.ea > lim || (u32)(addr.ea + size - 1) > lim)
+ if (addr.ea > lim)
goto bad;
+ *max_size = min_t(u64, ~0u, (u64)lim + 1 - addr.ea);
}
+ if (size > *max_size)
+ goto bad;
cpl = ctxt->ops->cpl(ctxt);
if (!(desc.type & 8)) {
/* data segment */
return X86EMUL_CONTINUE;
bad:
if (addr.seg == VCPU_SREG_SS)
- return emulate_ss(ctxt, sel);
+ return emulate_ss(ctxt, 0);
else
- return emulate_gp(ctxt, sel);
+ return emulate_gp(ctxt, 0);
}
static int linearize(struct x86_emulate_ctxt *ctxt,
unsigned size, bool write,
ulong *linear)
{
- return __linearize(ctxt, addr, size, write, false, linear);
+ unsigned max_size;
+ return __linearize(ctxt, addr, &max_size, size, write, false, linear);
}
static int __do_insn_fetch_bytes(struct x86_emulate_ctxt *ctxt, int op_size)
{
int rc;
- unsigned size;
+ unsigned size, max_size;
unsigned long linear;
int cur_size = ctxt->fetch.end - ctxt->fetch.data;
struct segmented_address addr = { .seg = VCPU_SREG_CS,
.ea = ctxt->eip + cur_size };
- size = 15UL ^ cur_size;
- rc = __linearize(ctxt, addr, size, false, true, &linear);
+ /*
+ * We do not know exactly how many bytes will be needed, and
+ * __linearize is expensive, so fetch as much as possible. We
+ * just have to avoid going beyond the 15 byte limit, the end
+ * of the segment, or the end of the page.
+ *
+ * __linearize is called with size 0 so that it does not do any
+ * boundary check itself. Instead, we use max_size to check
+ * against op_size.
+ */
+ rc = __linearize(ctxt, addr, &max_size, 0, false, true, &linear);
if (unlikely(rc != X86EMUL_CONTINUE))
return rc;
+ size = min_t(unsigned, 15UL ^ cur_size, max_size);
size = min_t(unsigned, size, PAGE_SIZE - offset_in_page(linear));
/*
* still, we must have hit the 15-byte boundary.
*/
if (unlikely(size < op_size))
- return X86EMUL_UNHANDLEABLE;
+ return emulate_gp(ctxt, 0);
+
rc = ctxt->ops->fetch(ctxt, linear, ctxt->fetch.end,
size, &ctxt->exception);
if (unlikely(rc != X86EMUL_CONTINUE))
rc = assign_eip_far(ctxt, ctxt->src.val, new_desc.l);
if (rc != X86EMUL_CONTINUE) {
- WARN_ON(!ctxt->mode != X86EMUL_MODE_PROT64);
+ WARN_ON(ctxt->mode != X86EMUL_MODE_PROT64);
/* assigning eip failed; restore the old cs */
ops->set_segment(ctxt, old_sel, &old_desc, 0, VCPU_SREG_CS);
return rc;
return rc;
rc = assign_eip_far(ctxt, eip, new_desc.l);
if (rc != X86EMUL_CONTINUE) {
- WARN_ON(!ctxt->mode != X86EMUL_MODE_PROT64);
+ WARN_ON(ctxt->mode != X86EMUL_MODE_PROT64);
ops->set_segment(ctxt, old_cs, &old_desc, 0, VCPU_SREG_CS);
}
return rc;
vmcs_write32(TPR_THRESHOLD, 0);
}
- kvm_vcpu_reload_apic_access_page(vcpu);
+ kvm_make_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu);
if (vmx_vm_has_apicv(vcpu->kvm))
memset(&vmx->pi_desc, 0, sizeof(struct pi_desc));
const unsigned long *fields = shadow_read_write_fields;
const int num_fields = max_shadow_read_write_fields;
+ preempt_disable();
+
vmcs_load(shadow_vmcs);
for (i = 0; i < num_fields; i++) {
vmcs_clear(shadow_vmcs);
vmcs_load(vmx->loaded_vmcs->vmcs);
+
+ preempt_enable();
}
static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
psize = page_level_size(level);
pmask = page_level_mask(level);
offset = virt_addr & ~pmask;
- phys_addr = pte_pfn(*pte) << PAGE_SHIFT;
+ phys_addr = (phys_addr_t)pte_pfn(*pte) << PAGE_SHIFT;
return (phys_addr | offset);
}
EXPORT_SYMBOL_GPL(slow_virt_to_phys);
mp_irq.dstapic = MP_APIC_ALL;
mp_irq.dstirq = pentry->irq;
mp_save_irq(&mp_irq);
+ mp_map_gsi_to_irq(pentry->irq, IOAPIC_MAP_ALLOC);
}
return 0;
mp_irq.dstapic = MP_APIC_ALL;
mp_irq.dstirq = pentry->irq;
mp_save_irq(&mp_irq);
+ mp_map_gsi_to_irq(pentry->irq, IOAPIC_MAP_ALLOC);
}
return 0;
}
{
bool no_sg_merge = !!test_bit(QUEUE_FLAG_NO_SG_MERGE,
&q->queue_flags);
+ bool merge_not_need = bio->bi_vcnt < queue_max_segments(q);
if (no_sg_merge && !bio_flagged(bio, BIO_CLONED) &&
- bio->bi_vcnt < queue_max_segments(q))
+ merge_not_need)
bio->bi_phys_segments = bio->bi_vcnt;
else {
struct bio *nxt = bio->bi_next;
bio->bi_next = NULL;
bio->bi_phys_segments = __blk_recalc_rq_segments(q, bio,
- no_sg_merge);
+ no_sg_merge && merge_not_need);
bio->bi_next = nxt;
}
}
err = e->ops.elevator_init_fn(q, e);
- return 0;
+ if (err)
+ elevator_put(e);
+ return err;
}
EXPORT_SYMBOL(elevator_init);
if (bytes && blk_rq_map_kern(q, rq, buffer, bytes, __GFP_WAIT)) {
err = DRIVER_ERROR << 24;
- goto out;
+ goto error;
}
memset(sense, 0, sizeof(sense));
blk_execute_rq(q, disk, rq, 0);
-out:
err = rq->errors & 0xff; /* only 8 bit SCSI status */
if (err) {
if (rq->sense_len && rq->sense) {
static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
+static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */
/* --------------------------------------------------------------------------
* Transaction Management
}
return wakeup;
} else {
- /*
- * There is firmware refusing to respond QR_EC when SCI_EVT
- * is not set, for which case, we complete the QR_EC
- * without issuing it to the firmware.
- * https://bugzilla.kernel.org/show_bug.cgi?id=86211
- */
- if (!(status & ACPI_EC_FLAG_SCI) &&
+ if (EC_FLAGS_QUERY_HANDSHAKE &&
+ !(status & ACPI_EC_FLAG_SCI) &&
(t->command == ACPI_EC_COMMAND_QUERY)) {
t->flags |= ACPI_EC_COMMAND_POLL;
t->rdata[t->ri++] = 0x00;
pr_debug("***** Command(%s) started *****\n",
acpi_ec_cmd_string(t->command));
start_transaction(ec);
- spin_unlock_irqrestore(&ec->lock, tmp);
- ret = ec_poll(ec);
- spin_lock_irqsave(&ec->lock, tmp);
if (ec->curr->command == ACPI_EC_COMMAND_QUERY) {
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
pr_debug("***** Event stopped *****\n");
}
+ spin_unlock_irqrestore(&ec->lock, tmp);
+ ret = ec_poll(ec);
+ spin_lock_irqsave(&ec->lock, tmp);
pr_debug("***** Command(%s) stopped *****\n",
acpi_ec_cmd_string(t->command));
ec->curr = NULL;
return 0;
}
+/*
+ * Acer EC firmware refuses to respond QR_EC when SCI_EVT is not set, for
+ * which case, we complete the QR_EC without issuing it to the firmware.
+ * https://bugzilla.kernel.org/show_bug.cgi?id=86211
+ */
+static int ec_flag_query_handshake(const struct dmi_system_id *id)
+{
+ pr_debug("Detected the EC firmware requiring QR_EC issued when SCI_EVT set\n");
+ EC_FLAGS_QUERY_HANDSHAKE = 1;
+ return 0;
+}
+
/*
* On some hardware it is necessary to clear events accumulated by the EC during
* sleep. These ECs stop reporting GPEs until they are manually polled, if too
{
ec_clear_on_resume, "Samsung hardware", {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
+ {
+ ec_flag_query_handshake, "Acer hardware", {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), }, NULL},
{},
};
return len;
}
+/*
+ * acpi_companion_match() - Can we match via ACPI companion device
+ * @dev: Device in question
+ *
+ * Check if the given device has an ACPI companion and if that companion has
+ * a valid list of PNP IDs, and if the device is the first (primary) physical
+ * device associated with it.
+ *
+ * If multiple physical devices are attached to a single ACPI companion, we need
+ * to be careful. The usage scenario for this kind of relationship is that all
+ * of the physical devices in question use resources provided by the ACPI
+ * companion. A typical case is an MFD device where all the sub-devices share
+ * the parent's ACPI companion. In such cases we can only allow the primary
+ * (first) physical device to be matched with the help of the companion's PNP
+ * IDs.
+ *
+ * Additional physical devices sharing the ACPI companion can still use
+ * resources available from it but they will be matched normally using functions
+ * provided by their bus types (and analogously for their modalias).
+ */
+static bool acpi_companion_match(const struct device *dev)
+{
+ struct acpi_device *adev;
+ bool ret;
+
+ adev = ACPI_COMPANION(dev);
+ if (!adev)
+ return false;
+
+ if (list_empty(&adev->pnp.ids))
+ return false;
+
+ mutex_lock(&adev->physical_node_lock);
+ if (list_empty(&adev->physical_node_list)) {
+ ret = false;
+ } else {
+ const struct acpi_device_physical_node *node;
+
+ node = list_first_entry(&adev->physical_node_list,
+ struct acpi_device_physical_node, node);
+ ret = node->dev == dev;
+ }
+ mutex_unlock(&adev->physical_node_lock);
+
+ return ret;
+}
+
/*
* Creates uevent modalias field for ACPI enumerated devices.
* Because the other buses does not support ACPI HIDs & CIDs.
*/
int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
{
- struct acpi_device *acpi_dev;
int len;
- acpi_dev = ACPI_COMPANION(dev);
- if (!acpi_dev)
- return -ENODEV;
-
- /* Fall back to bus specific way of modalias exporting */
- if (list_empty(&acpi_dev->pnp.ids))
+ if (!acpi_companion_match(dev))
return -ENODEV;
if (add_uevent_var(env, "MODALIAS="))
return -ENOMEM;
- len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
+ len = create_modalias(ACPI_COMPANION(dev), &env->buf[env->buflen - 1],
sizeof(env->buf) - env->buflen);
if (len <= 0)
return len;
*/
int acpi_device_modalias(struct device *dev, char *buf, int size)
{
- struct acpi_device *acpi_dev;
int len;
- acpi_dev = ACPI_COMPANION(dev);
- if (!acpi_dev)
+ if (!acpi_companion_match(dev))
return -ENODEV;
- /* Fall back to bus specific way of modalias exporting */
- if (list_empty(&acpi_dev->pnp.ids))
- return -ENODEV;
-
- len = create_modalias(acpi_dev, buf, size -1);
+ len = create_modalias(ACPI_COMPANION(dev), buf, size -1);
if (len <= 0)
return len;
buf[len++] = '\n';
if (!ids || !handle || acpi_bus_get_device(handle, &adev))
return NULL;
+ if (!acpi_companion_match(dev))
+ return NULL;
+
return __acpi_match_device(adev, ids);
}
EXPORT_SYMBOL_GPL(acpi_match_device);
#undef pr_fmt
#define pr_fmt(fmt) fmt
-static void rmem_cma_device_init(struct reserved_mem *rmem, struct device *dev)
+static int rmem_cma_device_init(struct reserved_mem *rmem, struct device *dev)
{
dev_set_cma_area(dev, rmem->priv);
+ return 0;
}
static void rmem_cma_device_release(struct reserved_mem *rmem,
}
mutex_unlock(&dpm_list_mtx);
async_synchronize_full();
+ if (!error)
+ error = async_error;
if (error) {
suspend_stats.failed_suspend_late++;
dpm_save_failed_step(SUSPEND_SUSPEND_LATE);
static const struct pci_device_id bcma_pci_bridge_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4313) },
- { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43224) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43224) }, /* 0xa8d8 */
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
- { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43227) }, /* 0xA8DB */
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43227) }, /* 0xa8db, BCM43217 (sic!) */
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43228) }, /* 0xa8dc */
{ 0, },
};
MODULE_DEVICE_TABLE(pci, bcma_pci_bridge_tbl);
return false;
}
-#ifdef CONFIG_OF
+#if defined(CONFIG_OF) && defined(CONFIG_OF_ADDRESS)
static struct device_node *bcma_of_find_child_device(struct platform_device *parent,
struct bcma_device *core)
{
ret = setup_commands(nq);
if (ret)
- goto err_queue;
+ return ret;
nullb->nr_queues++;
}
-
return 0;
-err_queue:
- cleanup_queues(nullb);
- return ret;
}
static int null_add_dev(void)
goto out_cleanup_queues;
}
blk_queue_make_request(nullb->q, null_queue_bio);
- init_driver_queues(nullb);
+ rv = init_driver_queues(nullb);
+ if (rv)
+ goto out_cleanup_blk_queue;
} else {
nullb->q = blk_init_queue_node(null_request_fn, &nullb->lock, home_node);
if (!nullb->q) {
}
blk_queue_prep_rq(nullb->q, null_rq_prep_fn);
blk_queue_softirq_done(nullb->q, null_softirq_done_fn);
- init_driver_queues(nullb);
+ rv = init_driver_queues(nullb);
+ if (rv)
+ goto out_cleanup_blk_queue;
}
nullb->q->queuedata = nullb;
u8 vdisk_mtype;
char disk_name[32];
-
- struct vio_disk_vtoc label;
};
static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio)
if (comp.err)
return comp.err;
- err = generic_request(port, VD_OP_GET_VTOC,
- &port->label, sizeof(port->label));
- if (err < 0) {
- printk(KERN_ERR PFX "VD_OP_GET_VTOC returns error %d\n", err);
- return err;
- }
-
if (vdc_version_supported(port, 1, 1)) {
/* vdisk_size should be set during the handshake, if it wasn't
* then the underlying disk is reserved by another system
{
u64 val = 0;
struct zram *zram = dev_to_zram(dev);
- struct zram_meta *meta = zram->meta;
down_read(&zram->init_lock);
- if (init_done(zram))
+ if (init_done(zram)) {
+ struct zram_meta *meta = zram->meta;
val = zs_get_total_pages(meta->mem_pool);
+ }
up_read(&zram->init_lock);
return scnprintf(buf, PAGE_SIZE, "%llu\n", val << PAGE_SHIFT);
int err;
unsigned long val;
struct zram *zram = dev_to_zram(dev);
- struct zram_meta *meta = zram->meta;
err = kstrtoul(buf, 10, &val);
if (err || val != 0)
return -EINVAL;
down_read(&zram->init_lock);
- if (init_done(zram))
+ if (init_done(zram)) {
+ struct zram_meta *meta = zram->meta;
atomic_long_set(&zram->stats.max_used_pages,
zs_get_total_pages(meta->mem_pool));
+ }
up_read(&zram->init_lock);
return len;
}
/* Error found so break the for loop */
- break;
+ return IRQ_HANDLED;
}
}
- return IRQ_HANDLED;
+
+ dev_err(l3->dev, "L3 %s IRQ not handled!!\n",
+ inttype ? "debug" : "application");
+
+ return IRQ_NONE;
}
static const struct of_device_id l3_noc_match[] = {
return ret;
}
+#ifdef CONFIG_PM
+
+/**
+ * l3_resume_noirq() - resume function for l3_noc
+ * @dev: pointer to l3_noc device structure
+ *
+ * We only have the resume handler only since we
+ * have already maintained the delta register
+ * configuration as part of configuring the system
+ */
+static int l3_resume_noirq(struct device *dev)
+{
+ struct omap_l3 *l3 = dev_get_drvdata(dev);
+ int i;
+ struct l3_flagmux_data *flag_mux;
+ void __iomem *base, *mask_regx = NULL;
+ u32 mask_val;
+
+ for (i = 0; i < l3->num_modules; i++) {
+ base = l3->l3_base[i];
+ flag_mux = l3->l3_flagmux[i];
+ if (!flag_mux->mask_app_bits && !flag_mux->mask_dbg_bits)
+ continue;
+
+ mask_regx = base + flag_mux->offset + L3_FLAGMUX_MASK0 +
+ (L3_APPLICATION_ERROR << 3);
+ mask_val = readl_relaxed(mask_regx);
+ mask_val &= ~(flag_mux->mask_app_bits);
+
+ writel_relaxed(mask_val, mask_regx);
+ mask_regx = base + flag_mux->offset + L3_FLAGMUX_MASK0 +
+ (L3_DEBUG_ERROR << 3);
+ mask_val = readl_relaxed(mask_regx);
+ mask_val &= ~(flag_mux->mask_dbg_bits);
+
+ writel_relaxed(mask_val, mask_regx);
+ }
+
+ /* Dummy read to force OCP barrier */
+ if (mask_regx)
+ (void)readl(mask_regx);
+
+ return 0;
+}
+
+static const struct dev_pm_ops l3_dev_pm_ops = {
+ .resume_noirq = l3_resume_noirq,
+};
+
+#define L3_DEV_PM_OPS (&l3_dev_pm_ops)
+#else
+#define L3_DEV_PM_OPS NULL
+#endif
+
static struct platform_driver omap_l3_driver = {
.probe = omap_l3_probe,
.driver = {
.name = "omap_l3_noc",
.owner = THIS_MODULE,
+ .pm = L3_DEV_PM_OPS,
.of_match_table = of_match_ptr(l3_noc_match),
},
};
static const struct file_operations raw_fops = {
.read = new_sync_read,
- .read_iter = generic_file_read_iter,
+ .read_iter = blkdev_read_iter,
.write = new_sync_write,
.write_iter = blkdev_write_iter,
.fsync = blkdev_fsync,
arch_timer_probed(int type, const struct of_device_id *matches)
{
struct device_node *dn;
- bool probed = false;
+ bool probed = true;
dn = of_find_matching_node(NULL, matches);
- if (dn && of_device_is_available(dn) && (arch_timers_present & type))
- probed = true;
+ if (dn && of_device_is_available(dn) && !(arch_timers_present & type))
+ probed = false;
of_node_put(dn);
return probed;
struct device *cpu_dev;
struct regulator *cpu_reg;
struct clk *cpu_clk;
+ unsigned long min_uV = ~0, max_uV = 0;
unsigned int transition_latency;
int ret;
/* OPPs might be populated at runtime, don't check for error here */
of_init_opp_table(cpu_dev);
- ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
- if (ret) {
- dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
- goto out_put_node;
- }
-
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
ret = -ENOMEM;
- goto out_free_table;
+ goto out_put_node;
}
of_property_read_u32(np, "voltage-tolerance", &priv->voltage_tolerance);
transition_latency = CPUFREQ_ETERNAL;
if (!IS_ERR(cpu_reg)) {
- struct dev_pm_opp *opp;
- unsigned long min_uV, max_uV;
- int i;
+ unsigned long opp_freq = 0;
/*
- * OPP is maintained in order of increasing frequency, and
- * freq_table initialised from OPP is therefore sorted in the
- * same order.
+ * Disable any OPPs where the connected regulator isn't able to
+ * provide the specified voltage and record minimum and maximum
+ * voltage levels.
*/
- for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
- ;
- rcu_read_lock();
- opp = dev_pm_opp_find_freq_exact(cpu_dev,
- freq_table[0].frequency * 1000, true);
- min_uV = dev_pm_opp_get_voltage(opp);
- opp = dev_pm_opp_find_freq_exact(cpu_dev,
- freq_table[i-1].frequency * 1000, true);
- max_uV = dev_pm_opp_get_voltage(opp);
- rcu_read_unlock();
+ while (1) {
+ struct dev_pm_opp *opp;
+ unsigned long opp_uV, tol_uV;
+
+ rcu_read_lock();
+ opp = dev_pm_opp_find_freq_ceil(cpu_dev, &opp_freq);
+ if (IS_ERR(opp)) {
+ rcu_read_unlock();
+ break;
+ }
+ opp_uV = dev_pm_opp_get_voltage(opp);
+ rcu_read_unlock();
+
+ tol_uV = opp_uV * priv->voltage_tolerance / 100;
+ if (regulator_is_supported_voltage(cpu_reg, opp_uV,
+ opp_uV + tol_uV)) {
+ if (opp_uV < min_uV)
+ min_uV = opp_uV;
+ if (opp_uV > max_uV)
+ max_uV = opp_uV;
+ } else {
+ dev_pm_opp_disable(cpu_dev, opp_freq);
+ }
+
+ opp_freq++;
+ }
+
ret = regulator_set_voltage_time(cpu_reg, min_uV, max_uV);
if (ret > 0)
transition_latency += ret * 1000;
}
+ ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
+ if (ret) {
+ pr_err("failed to init cpufreq table: %d\n", ret);
+ goto out_free_priv;
+ }
+
/*
* For now, just loading the cooling device;
* thermal DT code takes care of matching them.
policy->cpuinfo.transition_latency = transition_latency;
pd = cpufreq_get_driver_data();
- if (pd && !pd->independent_clocks)
+ if (!pd || !pd->independent_clocks)
cpumask_setall(policy->cpus);
of_node_put(np);
out_cooling_unregister:
cpufreq_cooling_unregister(priv->cdev);
- kfree(priv);
-out_free_table:
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
+out_free_priv:
+ kfree(priv);
out_put_node:
of_node_put(np);
out_put_reg_clk:
if (apiexcp & UECC_EXCP_DETECTED) {
cpc925_mc_printk(mci, KERN_INFO, "DRAM UECC Fault\n");
- edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
+ edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
pfn, offset, 0,
csrow, -1, -1,
mci->ctl_name, "");
static void process_ce_no_info(struct mem_ctl_info *mci)
{
edac_dbg(3, "\n");
- edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0, -1, -1, -1,
+ edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 0, 0, 0, -1, -1, -1,
"e7xxx CE log register overflow", "");
}
-1, -1,
"i3000 UE", "");
} else if (log & I3200_ECCERRLOG_CE) {
- edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
+ edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
0, 0, eccerrlog_syndrome(log),
eccerrlog_row(channel, log),
-1, -1,
- "i3000 UE", "");
+ "i3000 CE", "");
}
}
}
dimm->location[0], dimm->location[1], -1,
"i82860 UE", "");
else
- edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
+ edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
info->eap, 0, info->derrsyn,
dimm->location[0], dimm->location[1], -1,
"i82860 CE", "");
* Tell the DRM core that vblank IRQs aren't going to happen for
* a while. This cleans up any pending vblank events for us.
*/
- drm_vblank_off(dev, dcrtc->num);
+ drm_crtc_vblank_off(&dcrtc->crtc);
/* Handle any pending flip event. */
spin_lock_irq(&dev->event_lock);
armada_drm_crtc_update(dcrtc);
if (dpms_blanked(dpms))
armada_drm_vblank_off(dcrtc);
+ else
+ drm_crtc_vblank_on(&dcrtc->crtc);
}
}
/* Wait for pending flips to complete */
wait_event(dcrtc->frame_wait, !dcrtc->frame_work);
- drm_vblank_pre_modeset(crtc->dev, dcrtc->num);
+ drm_crtc_vblank_off(crtc);
crtc->mode = *adj;
armada_drm_crtc_update(dcrtc);
- drm_vblank_post_modeset(crtc->dev, dcrtc->num);
+ drm_crtc_vblank_on(crtc);
armada_drm_crtc_finish_fb(dcrtc, old_fb, dpms_blanked(dcrtc->dpms));
return 0;
armada_reg_queue_end(work->regs, i);
/*
- * Hold the old framebuffer for the work - DRM appears to drop our
- * reference to the old framebuffer in drm_mode_page_flip_ioctl().
+ * Ensure that we hold a reference on the new framebuffer.
+ * This has to match the behaviour in mode_set.
*/
- drm_framebuffer_reference(work->old_fb);
+ drm_framebuffer_reference(fb);
ret = armada_drm_crtc_queue_frame_work(dcrtc, work);
if (ret) {
- /*
- * Undo our reference above; DRM does not drop the reference
- * to this object on error, so that's okay.
- */
- drm_framebuffer_unreference(work->old_fb);
+ /* Undo our reference above */
+ drm_framebuffer_unreference(fb);
kfree(work);
return ret;
}
if (ret)
goto err_comp;
+ dev->irq_enabled = true;
dev->vblank_disable_allowed = 1;
ret = armada_fbdev_init(dev);
.desc = "Armada SoC DRM",
.date = "20120730",
.driver_features = DRIVER_GEM | DRIVER_MODESET |
- DRIVER_PRIME,
+ DRIVER_HAVE_IRQ | DRIVER_PRIME,
.ioctls = armada_ioctls,
.fops = &armada_drm_fops,
};
void *data)
{
struct exynos_drm_display *display = dev_get_drvdata(dev);
- struct exynos_dp_device *dp = display->ctx;
- struct drm_encoder *encoder = dp->encoder;
exynos_dp_dpms(display, DRM_MODE_DPMS_OFF);
-
- exynos_dp_connector_destroy(&dp->connector);
- encoder->funcs->destroy(encoder);
}
static const struct component_ops exynos_dp_ops = {
!atomic_read(&exynos_crtc->pending_flip),
HZ/20))
atomic_set(&exynos_crtc->pending_flip, 0);
- drm_vblank_off(crtc->dev, exynos_crtc->pipe);
+ drm_crtc_vblank_off(crtc);
}
if (manager->ops->dpms)
manager->ops->dpms(manager, mode);
exynos_crtc->dpms = mode;
+
+ if (mode == DRM_MODE_DPMS_ON)
+ drm_crtc_vblank_on(crtc);
}
static void exynos_drm_crtc_prepare(struct drm_crtc *crtc)
int exynos_dpi_remove(struct device *dev)
{
- struct drm_encoder *encoder = exynos_dpi_display.encoder;
struct exynos_dpi *ctx = exynos_dpi_display.ctx;
exynos_dpi_dpms(&exynos_dpi_display, DRM_MODE_DPMS_OFF);
- exynos_dpi_connector_destroy(&ctx->connector);
- encoder->funcs->destroy(encoder);
-
if (ctx->panel)
drm_panel_detach(ctx->panel);
plane = exynos_plane_init(dev, possible_crtcs,
DRM_PLANE_TYPE_OVERLAY);
- if (IS_ERR(plane))
- goto err_mode_config_cleanup;
- }
-
- /* init kms poll for handling hpd */
- drm_kms_helper_poll_init(dev);
+ if (!IS_ERR(plane))
+ continue;
- ret = drm_vblank_init(dev, MAX_CRTC);
- if (ret)
+ ret = PTR_ERR(plane);
goto err_mode_config_cleanup;
+ }
/* setup possible_clones. */
exynos_drm_encoder_setup(dev);
/* Try to bind all sub drivers. */
ret = component_bind_all(dev->dev, dev);
if (ret)
- goto err_cleanup_vblank;
+ goto err_mode_config_cleanup;
- /* Probe non kms sub drivers and virtual display driver. */
- ret = exynos_drm_device_subdrv_probe(dev);
+ ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
if (ret)
goto err_unbind_all;
- /* force connectors detection */
- drm_helper_hpd_irq_event(dev);
+ /* Probe non kms sub drivers and virtual display driver. */
+ ret = exynos_drm_device_subdrv_probe(dev);
+ if (ret)
+ goto err_cleanup_vblank;
/*
* enable drm irq mode.
*/
dev->vblank_disable_allowed = true;
+ /* init kms poll for handling hpd */
+ drm_kms_helper_poll_init(dev);
+
+ /* force connectors detection */
+ drm_helper_hpd_irq_event(dev);
+
return 0;
-err_unbind_all:
- component_unbind_all(dev->dev, dev);
err_cleanup_vblank:
drm_vblank_cleanup(dev);
+err_unbind_all:
+ component_unbind_all(dev->dev, dev);
err_mode_config_cleanup:
drm_mode_config_cleanup(dev);
drm_release_iommu_mapping(dev);
exynos_drm_fbdev_fini(dev);
drm_kms_helper_poll_fini(dev);
- component_unbind_all(dev->dev, dev);
drm_vblank_cleanup(dev);
+ component_unbind_all(dev->dev, dev);
drm_mode_config_cleanup(dev);
drm_release_iommu_mapping(dev);
drm_modeset_lock_all(dev);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- if (connector->funcs->dpms)
- connector->funcs->dpms(connector, connector->dpms);
+ if (connector->funcs->dpms) {
+ int dpms = connector->dpms;
+
+ connector->dpms = DRM_MODE_DPMS_OFF;
+ connector->funcs->dpms(connector, dpms);
+ }
}
drm_modeset_unlock_all(dev);
void *data)
{
struct exynos_dsi *dsi = exynos_dsi_display.ctx;
- struct drm_encoder *encoder = dsi->encoder;
exynos_dsi_dpms(&exynos_dsi_display, DRM_MODE_DPMS_OFF);
- exynos_dsi_connector_destroy(&dsi->connector);
- encoder->funcs->destroy(encoder);
-
mipi_dsi_host_unregister(&dsi->dsi_host);
}
{
struct exynos_drm_manager *mgr = platform_get_drvdata(pdev);
struct vidi_context *ctx = mgr->ctx;
- struct drm_encoder *encoder = ctx->encoder;
if (ctx->raw_edid != (struct edid *)fake_edid_info) {
kfree(ctx->raw_edid);
return -EINVAL;
}
- encoder->funcs->destroy(encoder);
- drm_connector_cleanup(&ctx->connector);
-
return 0;
}
static void hdmi_unbind(struct device *dev, struct device *master, void *data)
{
- struct exynos_drm_display *display = get_hdmi_display(dev);
- struct drm_encoder *encoder = display->encoder;
- struct hdmi_context *hdata = display->ctx;
-
- hdmi_connector_destroy(&hdata->connector);
- encoder->funcs->destroy(encoder);
}
static const struct component_ops hdmi_component_ops = {
* BSpec erroneously claims we should aim for 4MHz, but
* in fact 1MHz is the correct frequency.
*/
- I915_WRITE(GMBUSFREQ_VLV, dev_priv->vlv_cdclk_freq);
+ I915_WRITE(GMBUSFREQ_VLV, DIV_ROUND_UP(dev_priv->vlv_cdclk_freq, 1000));
}
/* Adjust CDclk dividers to allow high res or save power if possible */
/* Acer C720 Chromebook (Core i3 4005U) */
{ 0x0a16, 0x1025, 0x0a11, quirk_backlight_present },
+ /* Apple Macbook 2,1 (Core 2 T7400) */
+ { 0x27a2, 0x8086, 0x7270, quirk_backlight_present },
+
/* Toshiba CB35 Chromebook (Celeron 2955U) */
{ 0x0a06, 0x1179, 0x0a88, quirk_backlight_present },
ssize_t ret;
int i;
+ /*
+ * Sometime we just get the same incorrect byte repeated
+ * over the entire buffer. Doing just one throw away read
+ * initially seems to "solve" it.
+ */
+ drm_dp_dpcd_read(aux, DP_DPCD_REV, buffer, 1);
+
for (i = 0; i < 3; i++) {
ret = drm_dp_dpcd_read(aux, offset, buffer, size);
if (ret == size)
}
}
- /* Training Pattern 3 support */
+ /* Training Pattern 3 support, both source and sink */
if (intel_dp->dpcd[DP_DPCD_REV] >= 0x12 &&
- intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_TPS3_SUPPORTED) {
+ intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_TPS3_SUPPORTED &&
+ (IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8)) {
intel_dp->use_tps3 = true;
DRM_DEBUG_KMS("Displayport TPS3 supported\n");
} else
if (intel_dig_port->base.type != INTEL_OUTPUT_EDP)
intel_dig_port->base.type = INTEL_OUTPUT_DISPLAYPORT;
+ if (long_hpd && intel_dig_port->base.type == INTEL_OUTPUT_EDP) {
+ /*
+ * vdd off can generate a long pulse on eDP which
+ * would require vdd on to handle it, and thus we
+ * would end up in an endless cycle of
+ * "vdd off -> long hpd -> vdd on -> detect -> vdd off -> ..."
+ */
+ DRM_DEBUG_KMS("ignoring long hpd on eDP port %c\n",
+ port_name(intel_dig_port->port));
+ return false;
+ }
+
DRM_DEBUG_KMS("got hpd irq on port %c - %s\n",
port_name(intel_dig_port->port),
long_hpd ? "long" : "short");
u32 vgt_cache_invalidation;
u32 hdp_host_path_cntl, tmp;
u32 disabled_rb_mask;
- int i, j, num_shader_engines, ps_thread_count;
+ int i, j, ps_thread_count;
switch (rdev->family) {
case CHIP_CYPRESS:
rdev->config.evergreen.tile_config |=
((gb_addr_config & 0x30000000) >> 28) << 12;
- num_shader_engines = (gb_addr_config & NUM_SHADER_ENGINES(3) >> 12) + 1;
-
if ((rdev->family >= CHIP_CEDAR) && (rdev->family <= CHIP_HEMLOCK)) {
u32 efuse_straps_4;
u32 efuse_straps_3;
pi->sram_end = SMC_RAM_END;
- pi->enable_nb_dpm = true;
+ /* Enabling nb dpm on an asrock system prevents dpm from working */
+ if (rdev->pdev->subsystem_vendor == 0x1849)
+ pi->enable_nb_dpm = false;
+ else
+ pi->enable_nb_dpm = true;
pi->caps_power_containment = true;
pi->caps_cac = true;
pi->caps_sclk_ds = true;
pi->enable_auto_thermal_throttling = true;
pi->disable_nb_ps3_in_battery = false;
- if (radeon_bapm == 0)
+ if (radeon_bapm == -1) {
+ /* There are stability issues reported on with
+ * bapm enabled on an asrock system.
+ */
+ if (rdev->pdev->subsystem_vendor == 0x1849)
+ pi->bapm_enable = false;
+ else
+ pi->bapm_enable = true;
+ } else if (radeon_bapm == 0) {
pi->bapm_enable = false;
- else
+ } else {
pi->bapm_enable = true;
+ }
pi->voltage_drop_t = 0;
pi->caps_sclk_throttle_low_notification = false;
pi->caps_fps = false; /* true? */
r = igp_read_bios_from_vram(rdev);
if (r == false)
r = radeon_read_bios(rdev);
- if (r == false) {
+ if (r == false)
r = radeon_read_disabled_bios(rdev);
- }
- if (r == false) {
+ if (r == false)
r = radeon_read_platform_bios(rdev);
- }
if (r == false || rdev->bios == NULL) {
DRM_ERROR("Unable to locate a BIOS ROM\n");
rdev->bios = NULL;
kfree(parser->track);
kfree(parser->relocs);
kfree(parser->relocs_ptr);
- kfree(parser->vm_bos);
+ drm_free_large(parser->vm_bos);
for (i = 0; i < parser->nchunks; i++)
drm_free_large(parser->chunks[i].kdata);
kfree(parser->chunks);
}
/* and then save the content of the ring */
- *data = kmalloc_array(size, sizeof(uint32_t), GFP_KERNEL);
+ *data = drm_malloc_ab(size, sizeof(uint32_t));
if (!*data) {
mutex_unlock(&rdev->ring_lock);
return 0;
}
radeon_ring_unlock_commit(rdev, ring, false);
- kfree(data);
+ drm_free_large(data);
return 0;
}
struct radeon_cs_reloc *list;
unsigned i, idx;
- list = kmalloc_array(vm->max_pde_used + 2,
- sizeof(struct radeon_cs_reloc), GFP_KERNEL);
+ list = drm_malloc_ab(vm->max_pde_used + 2,
+ sizeof(struct radeon_cs_reloc));
if (!list)
return NULL;
if ((rps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) &&
index == 0) {
/* XXX disable for A0 tahiti */
- si_pi->ulv.supported = true;
+ si_pi->ulv.supported = false;
si_pi->ulv.pl = *pl;
si_pi->ulv.one_pcie_lane_in_ulv = false;
si_pi->ulv.volt_change_delay = SISLANDS_ULVVOLTAGECHANGEDELAY_DFLT;
struct drm_hash_item *hash;
int ret;
- ret = drm_ht_find_item(&man->resources, user_key, &hash);
+ ret = drm_ht_find_item(&man->resources, user_key | (res_type << 24),
+ &hash);
if (likely(ret != 0))
return -EINVAL;
goto out_err0;
}
- if (unlikely(dev_priv->prim_bb_mem < dev_priv->vram_size))
+ /*
+ * Limit back buffer size to VRAM size. Remove this once
+ * screen targets are implemented.
+ */
+ if (dev_priv->prim_bb_mem > dev_priv->vram_size)
dev_priv->prim_bb_mem = dev_priv->vram_size;
mutex_unlock(&dev_priv->hw_mutex);
* can do this since the caller in the drm core doesn't check anything
* which is protected by any looks.
*/
- drm_modeset_unlock(&crtc->mutex);
+ drm_modeset_unlock_crtc(crtc);
drm_modeset_lock_all(dev_priv->dev);
/* A lot of the code assumes this */
ret = 0;
out:
drm_modeset_unlock_all(dev_priv->dev);
- drm_modeset_lock(&crtc->mutex, NULL);
+ drm_modeset_lock_crtc(crtc);
return ret;
}
* can do this since the caller in the drm core doesn't check anything
* which is protected by any looks.
*/
- drm_modeset_unlock(&crtc->mutex);
+ drm_modeset_unlock_crtc(crtc);
drm_modeset_lock_all(dev_priv->dev);
vmw_cursor_update_position(dev_priv, shown,
du->cursor_y + du->hotspot_y);
drm_modeset_unlock_all(dev_priv->dev);
- drm_modeset_lock(&crtc->mutex, NULL);
+ drm_modeset_lock_crtc(crtc);
return 0;
}
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC)
};
int i;
+ u32 assumed_bpp = 2;
+
+ /*
+ * If using screen objects, then assume 32-bpp because that's what the
+ * SVGA device is assuming
+ */
+ if (dev_priv->sou_priv)
+ assumed_bpp = 4;
/* Add preferred mode */
{
mode->vdisplay = du->pref_height;
vmw_guess_mode_timing(mode);
- if (vmw_kms_validate_mode_vram(dev_priv, mode->hdisplay * 2,
- mode->vdisplay)) {
+ if (vmw_kms_validate_mode_vram(dev_priv,
+ mode->hdisplay * assumed_bpp,
+ mode->vdisplay)) {
drm_mode_probed_add(connector, mode);
} else {
drm_mode_destroy(dev, mode);
bmode->vdisplay > max_height)
continue;
- if (!vmw_kms_validate_mode_vram(dev_priv, bmode->hdisplay * 2,
+ if (!vmw_kms_validate_mode_vram(dev_priv,
+ bmode->hdisplay * assumed_bpp,
bmode->vdisplay))
continue;
[KEY_BRIGHTNESS_MIN] = "BrightnessMin",
[KEY_BRIGHTNESS_MAX] = "BrightnessMax",
[KEY_BRIGHTNESS_AUTO] = "BrightnessAuto",
+ [KEY_KBDINPUTASSIST_PREV] = "KbdInputAssistPrev",
+ [KEY_KBDINPUTASSIST_NEXT] = "KbdInputAssistNext",
+ [KEY_KBDINPUTASSIST_PREVGROUP] = "KbdInputAssistPrevGroup",
+ [KEY_KBDINPUTASSIST_NEXTGROUP] = "KbdInputAssistNextGroup",
+ [KEY_KBDINPUTASSIST_ACCEPT] = "KbdInputAssistAccept",
+ [KEY_KBDINPUTASSIST_CANCEL] = "KbdInputAssistCancel",
};
static const char *relatives[REL_MAX + 1] = {
#define USB_VENDOR_ID_ELAN 0x04f3
#define USB_DEVICE_ID_ELAN_TOUCHSCREEN 0x0089
+#define USB_DEVICE_ID_ELAN_TOUCHSCREEN_009B 0x009b
+#define USB_DEVICE_ID_ELAN_TOUCHSCREEN_016F 0x016f
#define USB_VENDOR_ID_ELECOM 0x056e
#define USB_DEVICE_ID_ELECOM_BM084 0x0061
break;
case 0x5b: /* TransducerSerialNumber */
- set_bit(MSC_SERIAL, input->mscbit);
+ usage->type = EV_MSC;
+ usage->code = MSC_SERIAL;
+ bit = input->mscbit;
+ max = MSC_MAX;
break;
default: goto unknown;
case 0x28b: map_key_clear(KEY_FORWARDMAIL); break;
case 0x28c: map_key_clear(KEY_SEND); break;
+ case 0x2c7: map_key_clear(KEY_KBDINPUTASSIST_PREV); break;
+ case 0x2c8: map_key_clear(KEY_KBDINPUTASSIST_NEXT); break;
+ case 0x2c9: map_key_clear(KEY_KBDINPUTASSIST_PREVGROUP); break;
+ case 0x2ca: map_key_clear(KEY_KBDINPUTASSIST_NEXTGROUP); break;
+ case 0x2cb: map_key_clear(KEY_KBDINPUTASSIST_ACCEPT); break;
+ case 0x2cc: map_key_clear(KEY_KBDINPUTASSIST_CANCEL); break;
+
default: goto ignore;
}
break;
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN, HID_QUIRK_ALWAYS_POLL },
+ { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_009B, HID_QUIRK_ALWAYS_POLL },
+ { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_016F, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
goto st_sensors_free_memory;
}
- for (i = 0; i < n * num_data_channels; i++) {
+ for (i = 0; i < n * byte_for_channel; i++) {
if (i < n)
buf[i] = rx_array[i];
else
err = __mlx4_ib_create_flow(qp, flow_attr, domain, type[i],
&mflow->reg_id[i]);
if (err)
- goto err_free;
+ goto err_create_flow;
i++;
}
if (i < ARRAY_SIZE(type) && flow_attr->type == IB_FLOW_ATTR_NORMAL) {
err = mlx4_ib_tunnel_steer_add(qp, flow_attr, &mflow->reg_id[i]);
if (err)
- goto err_free;
+ goto err_create_flow;
+ i++;
}
return &mflow->ibflow;
+err_create_flow:
+ while (i) {
+ (void)__mlx4_ib_destroy_flow(to_mdev(qp->device)->dev, mflow->reg_id[i]);
+ i--;
+ }
err_free:
kfree(mflow);
return ERR_PTR(err);
opencores_kbd->addr = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(opencores_kbd->addr))
- error = PTR_ERR(opencores_kbd->addr);
+ return PTR_ERR(opencores_kbd->addr);
input->name = pdev->name;
input->phys = "opencores-kbd/input0";
.max_cols = 8,
.max_rows = 12,
.col_gpios = 0x0000ff, /* GPIO 0 - 7*/
- .row_gpios = 0x1fef00, /* GPIO 8-14, 16-20 */
+ .row_gpios = 0x1f7f00, /* GPIO 8-14, 16-20 */
},
[STMPE2403] = {
.auto_increment = true,
pcu->ofn_reg_addr = value;
mutex_unlock(&pcu->cmd_mutex);
- return error ?: count;
+ return count;
}
static DEVICE_ATTR(reg_addr, S_IRUGO | S_IWUSR,
struct ff_effect *effect)
{
struct max77693_haptic *haptic = input_get_drvdata(dev);
- uint64_t period_mag_multi;
+ u64 period_mag_multi;
haptic->magnitude = effect->u.rumble.strong_magnitude;
if (!haptic->magnitude)
* The formula to convert magnitude to pwm_duty as follows:
* - pwm_duty = (magnitude * pwm_period) / MAX_MAGNITUDE(0xFFFF)
*/
- period_mag_multi = (int64_t)(haptic->pwm_dev->period *
- haptic->magnitude);
+ period_mag_multi = (u64)haptic->pwm_dev->period * haptic->magnitude;
haptic->pwm_duty = (unsigned int)(period_mag_multi >>
MAX_MAGNITUDE_SHIFT);
struct gpio_desc *desc;
int gpio;
- desc = gpiod_get_index(dev, KBUILD_MODNAME, acpi_index);
+ desc = gpiod_get_index(dev, KBUILD_MODNAME, acpi_index, GPIOD_ASIS);
if (IS_ERR(desc))
return PTR_ERR(desc);
{
struct psmouse *psmouse = serio_get_drvdata(serio);
struct psmouse *parent = NULL;
- struct serio_driver *drv = serio->drv;
unsigned char type;
int rc = -1;
- if (!drv || !psmouse) {
- psmouse_dbg(psmouse,
- "reconnect request, but serio is disconnected, ignoring...\n");
- return -1;
- }
-
mutex_lock(&psmouse_mutex);
if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
if (num >= mouse->count) {
mouse->count = 0;
} else {
- memmove(mouse->buf, mouse->buf + num - 1, BUFLEN - num);
+ memmove(mouse->buf, mouse->buf + num, BUFLEN - num);
mouse->count -= num;
}
}
{
struct ps2if *ps2if = dev_id;
unsigned int status;
- int handled = IRQ_NONE;
+ irqreturn_t handled = IRQ_NONE;
while ((status = readl(ps2if->base)) & 0xffff0000) {
serio_interrupt(ps2if->io, status & 0xff, 0);
{
struct ps2if *ps2if = io->port_data;
- writel(0, ps2if->base); /* disable rx irq */
+ writel(0, ps2if->base + 4); /* disable rx irq */
}
/*
};
/*
- * Some laptops do implement active multiplexing mode correctly;
- * unfortunately they are in minority.
+ * Some Fujitsu notebooks are having trouble with touchpads if
+ * active multiplexing mode is activated. Luckily they don't have
+ * external PS/2 ports so we can safely disable it.
+ * ... apparently some Toshibas don't like MUX mode either and
+ * die horrible death on reboot.
*/
-static const struct dmi_system_id __initconst i8042_dmi_mux_table[] = {
+static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
+ {
+ /* Fujitsu Lifebook P7010/P7010D */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "P7010"),
+ },
+ },
+ {
+ /* Fujitsu Lifebook P7010 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "0000000000"),
+ },
+ },
+ {
+ /* Fujitsu Lifebook P5020D */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P Series"),
+ },
+ },
+ {
+ /* Fujitsu Lifebook S2000 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S Series"),
+ },
+ },
+ {
+ /* Fujitsu Lifebook S6230 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"),
+ },
+ },
+ {
+ /* Fujitsu T70H */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "FMVLT70H"),
+ },
+ },
+ {
+ /* Fujitsu-Siemens Lifebook T3010 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T3010"),
+ },
+ },
+ {
+ /* Fujitsu-Siemens Lifebook E4010 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E4010"),
+ },
+ },
+ {
+ /* Fujitsu-Siemens Amilo Pro 2010 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2010"),
+ },
+ },
+ {
+ /* Fujitsu-Siemens Amilo Pro 2030 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "AMILO PRO V2030"),
+ },
+ },
+ {
+ /*
+ * No data is coming from the touchscreen unless KBC
+ * is in legacy mode.
+ */
+ /* Panasonic CF-29 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"),
+ },
+ },
+ {
+ /*
+ * HP Pavilion DV4017EA -
+ * errors on MUX ports are reported without raising AUXDATA
+ * causing "spurious NAK" messages.
+ */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EA032EA#ABF)"),
+ },
+ },
+ {
+ /*
+ * HP Pavilion ZT1000 -
+ * like DV4017EA does not raise AUXERR for errors on MUX ports.
+ */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Notebook PC"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook ZT1000"),
+ },
+ },
+ {
+ /*
+ * HP Pavilion DV4270ca -
+ * like DV4017EA does not raise AUXERR for errors on MUX ports.
+ */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EH476UA#ABL)"),
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P10"),
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "EQUIUM A110"),
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE C850D"),
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Sentia"),
+ },
+ },
+ {
+ /* Sharp Actius MM20 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SHARP"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "PC-MM20 Series"),
+ },
+ },
+ {
+ /* Sony Vaio FS-115b */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FS115B"),
+ },
+ },
+ {
+ /*
+ * Sony Vaio FZ-240E -
+ * reset and GET ID commands issued via KBD port are
+ * sometimes being delivered to AUX3.
+ */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ240E"),
+ },
+ },
{
/*
- * Panasonic CF-18 needs to be in MUX mode since the
- * touchscreen is on serio3 and it also has touchpad.
+ * Most (all?) VAIOs do not have external PS/2 ports nor
+ * they implement active multiplexing properly, and
+ * MUX discovery usually messes up keyboard/touchpad.
*/
.matches = {
- DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"),
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_BOARD_NAME, "VAIO"),
+ },
+ },
+ {
+ /* Amoi M636/A737 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Amoi Electronics CO.,LTD."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "M636/A737 platform"),
+ },
+ },
+ {
+ /* Lenovo 3000 n100 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "076804U"),
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"),
+ },
+ },
+ {
+ /* Acer Aspire 5710 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5710"),
+ },
+ },
+ {
+ /* Gericom Bellagio */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Gericom"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "N34AS6"),
+ },
+ },
+ {
+ /* IBM 2656 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "2656"),
+ },
+ },
+ {
+ /* Dell XPS M1530 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "XPS M1530"),
+ },
+ },
+ {
+ /* Compal HEL80I */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "COMPAL"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HEL80I"),
+ },
+ },
+ {
+ /* Dell Vostro 1510 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Vostro1510"),
+ },
+ },
+ {
+ /* Acer Aspire 5536 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5536"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
+ },
+ },
+ {
+ /* Dell Vostro V13 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V13"),
+ },
+ },
+ {
+ /* Newer HP Pavilion dv4 models */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv4 Notebook PC"),
+ },
+ },
+ {
+ /* Asus X450LCP */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "X450LCP"),
+ },
+ },
+ {
+ /* Avatar AVIU-145A6 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "IC4I"),
},
},
{ }
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv4 Notebook PC"),
},
},
+ {
+ /* Fujitsu A544 laptop */
+ /* https://bugzilla.redhat.com/show_bug.cgi?id=1111138 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK A544"),
+ },
+ },
+ {
+ /* Fujitsu AH544 laptop */
+ /* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK AH544"),
+ },
+ },
{
/* Fujitsu U574 laptop */
/* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */
if (dmi_check_system(i8042_dmi_noloop_table))
i8042_noloop = true;
- if (dmi_check_system(i8042_dmi_mux_table))
- i8042_nomux = false;
+ if (dmi_check_system(i8042_dmi_nomux_table))
+ i8042_nomux = true;
if (dmi_check_system(i8042_dmi_notimeout_table))
i8042_notimeout = true;
module_param_named(noaux, i8042_noaux, bool, 0);
MODULE_PARM_DESC(noaux, "Do not probe or use AUX (mouse) port.");
-static bool i8042_nomux = true;
+static bool i8042_nomux;
module_param_named(nomux, i8042_nomux, bool, 0);
MODULE_PARM_DESC(nomux, "Do not check whether an active multiplexing controller is present.");
* Documentation/input/input-programming.txt for more details.
*/
-static int abs_x[3] = {350, 3900, 5};
+static int abs_x[3] = {150, 4000, 5};
module_param_array(abs_x, int, NULL, 0);
MODULE_PARM_DESC(abs_x, "Touchscreen absolute X min, max, fuzz");
-static int abs_y[3] = {320, 3750, 40};
+static int abs_y[3] = {200, 4000, 40};
module_param_array(abs_y, int, NULL, 0);
MODULE_PARM_DESC(abs_y, "Touchscreen absolute Y min, max, fuzz");
goto out;
}
+ /* create a nice device name */
+ sprintf(dev->name, "saa7146 (%d)", saa7146_num);
+
DEB_EE("pci:%p\n", pci);
err = pci_enable_device(pci);
/* the rest + print status message */
- /* create a nice device name */
- sprintf(dev->name, "saa7146 (%d)", saa7146_num);
-
pr_info("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x)\n",
dev->mem, dev->revision, pci->irq,
pci->subsystem_vendor, pci->subsystem_device);
break;
/* attach tuner */
+ memset(&m88ts2022_config, 0, sizeof(m88ts2022_config));
m88ts2022_config.fe = fe0->dvb.frontend;
m88ts2022_config.clock = 27000000;
memset(&info, 0, sizeof(struct i2c_board_info));
/* port c - terrestrial/cable */
case 2:
/* attach frontend */
+ memset(&si2168_config, 0, sizeof(si2168_config));
si2168_config.i2c_adapter = &adapter;
si2168_config.fe = &fe0->dvb.frontend;
si2168_config.ts_mode = SI2168_TS_SERIAL;
port->i2c_client_demod = client_demod;
/* attach tuner */
+ memset(&si2157_config, 0, sizeof(si2157_config));
si2157_config.fe = fe0->dvb.frontend;
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "si2157", I2C_NAME_SIZE);
config VIDEO_TW68
tristate "Techwell tw68x Video For Linux"
depends on VIDEO_DEV && PCI && VIDEO_V4L2
- select I2C_ALGOBIT
select VIDEOBUF2_DMA_SG
---help---
Support for Techwell tw68xx based frame grabber boards.
/* get irq */
err = devm_request_irq(&pci_dev->dev, pci_dev->irq, tw68_irq,
- IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
+ IRQF_SHARED, dev->name, dev);
if (err < 0) {
pr_err("%s: can't get IRQ %d\n",
dev->name, pci_dev->irq);
config VIDEO_SAMSUNG_S5P_G2D
tristate "Samsung S5P and EXYNOS4 G2D 2d graphics accelerator driver"
depends on VIDEO_DEV && VIDEO_V4L2
- depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST
+ depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
depends on HAS_DMA
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
config VIDEO_SAMSUNG_S5P_JPEG
tristate "Samsung S5P/Exynos3250/Exynos4 JPEG codec driver"
depends on VIDEO_DEV && VIDEO_V4L2
- depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST
+ depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
depends on HAS_DMA
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
config VIDEO_SAMSUNG_S5P_MFC
tristate "Samsung S5P MFC Video Codec"
depends on VIDEO_DEV && VIDEO_V4L2
- depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST
+ depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
depends on HAS_DMA
select VIDEOBUF2_DMA_CONTIG
default n
config VIDEO_SAMSUNG_EXYNOS4_IS
bool "Samsung S5P/EXYNOS4 SoC series Camera Subsystem driver"
depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
- depends on (PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST)
+ depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
depends on OF && COMMON_CLK
help
Say Y here to enable camera host interface devices for
return -ENXIO;
}
+#if defined(CONFIG_PM_RUNTIME) || defined(CONFIG_PM_SLEEP)
static int fimc_m2m_suspend(struct fimc_dev *fimc)
{
unsigned long flags;
return 0;
}
+#endif /* CONFIG_PM_RUNTIME || CONFIG_PM_SLEEP */
static const struct of_device_id fimc_of_match[];
unsigned long buffer, unsigned long size,
struct s5p_jpeg_ctx *ctx)
{
- int c, components, notfound;
+ int c, components = 0, notfound;
unsigned int height, width, word, subsampling = 0;
long length;
struct s5p_jpeg_buffer jpeg_buffer;
return 0;
}
+#if defined(CONFIG_PM_RUNTIME) || defined(CONFIG_PM_SLEEP)
static int s5p_jpeg_runtime_suspend(struct device *dev)
{
struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
return 0;
}
+#endif /* CONFIG_PM_RUNTIME || CONFIG_PM_SLEEP */
+#ifdef CONFIG_PM_SLEEP
static int s5p_jpeg_suspend(struct device *dev)
{
if (pm_runtime_suspended(dev))
return s5p_jpeg_runtime_resume(dev);
}
+#endif
static const struct dev_pm_ops s5p_jpeg_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(s5p_jpeg_suspend, s5p_jpeg_resume)
config VIDEO_SAMSUNG_S5P_TV
bool "Samsung TV driver for S5P platform"
depends on PM_RUNTIME
- depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST
+ depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
default n
---help---
Say Y here to enable selecting the TV output devices for
config VIDEO_VIVID
tristate "Virtual Video Test Driver"
- depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
+ depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 && FB
select FONT_SUPPORT
select FONT_8x16
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
select VIDEOBUF2_VMALLOC
default n
---help---
tpg->black_line[plane] = vzalloc(max_w * pixelsz);
if (!tpg->black_line[plane])
return -ENOMEM;
- tpg->random_line[plane] = vzalloc(max_w * pixelsz);
+ tpg->random_line[plane] = vzalloc(max_w * 2 * pixelsz);
if (!tpg->random_line[plane])
return -ENOMEM;
}
fmerr("Unable to read firmware(%s) content\n", fw_name);
return ret;
}
- fmdbg("Firmware(%s) length : %d bytes\n", fw_name, fw_entry->size);
+ fmdbg("Firmware(%s) length : %zu bytes\n", fw_name, fw_entry->size);
fw_data = (void *)fw_entry->data;
fw_len = fw_entry->size;
if (priv) {
cancel_delayed_work(&priv->timer_sleep);
- hybrid_tuner_release_state(priv);
if (priv->firmware)
release_firmware(priv->firmware);
+ hybrid_tuner_release_state(priv);
}
mutex_unlock(&xc5000_list_mutex);
return af9035_wr_regs(d, reg, &val, 1);
}
-static int af9035_add_i2c_dev(struct dvb_usb_device *d, char *type, u8 addr,
- void *platform_data, struct i2c_adapter *adapter)
+static int af9035_add_i2c_dev(struct dvb_usb_device *d, const char *type,
+ u8 addr, void *platform_data, struct i2c_adapter *adapter)
{
int ret, num;
struct state *state = d_to_priv(d);
goto err;
}
- request_module(board_info.type);
+ request_module("%s", board_info.type);
/* register I2C device */
client = i2c_new_device(adapter, &board_info);
return ret;
}
-static int anysee_add_i2c_dev(struct dvb_usb_device *d, char *type, u8 addr,
- void *platform_data)
+static int anysee_add_i2c_dev(struct dvb_usb_device *d, const char *type,
+ u8 addr, void *platform_data)
{
int ret, num;
struct anysee_state *state = d_to_priv(d);
goto err;
}
- request_module(board_info.type);
+ request_module("%s", board_info.type);
/* register I2C device */
client = i2c_new_device(adapter, &board_info);
int em28xx_audio_setup(struct em28xx *dev)
{
int vid1, vid2, feat, cfg;
- u32 vid;
+ u32 vid = 0;
u8 i2s_samplerates;
if (dev->chip_id == CHIP_ID_EM2870 ||
em28xx_info("Registering input extension\n");
ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+ if (!ir)
+ return -ENOMEM;
rc = rc_allocate_device();
- if (!ir || !rc)
+ if (!rc)
goto error;
/* record handles to ourself */
dev->bandwidth->val = bandwidth;
dev->bandwidth->cur.val = bandwidth;
- dev_dbg(dev->dev, "bandwidth selected=%d\n", bandwidth_lut[i].freq);
+ dev_dbg(dev->dev, "bandwidth selected=%d\n", bandwidth);
u16tmp = 0;
u16tmp |= ((bandwidth >> 0) & 0xff) << 0;
if (usbvision->remove_pending) {
printk(KERN_INFO "%s: Final disconnect\n", __func__);
usbvision_release(usbvision);
+ return 0;
}
mutex_unlock(&usbvision->v4l2_lock);
if (usbvision->remove_pending) {
printk(KERN_INFO "%s: Final disconnect\n", __func__);
usbvision_release(usbvision);
+ return err_code;
}
mutex_unlock(&usbvision->v4l2_lock);
stream->ctrl = probe;
stream->cur_format = format;
stream->cur_frame = frame;
- stream->frame_size = fmt->fmt.pix.sizeimage;
done:
mutex_unlock(&stream->mutex);
static void uvc_video_validate_buffer(const struct uvc_streaming *stream,
struct uvc_buffer *buf)
{
- if (stream->frame_size != buf->bytesused &&
+ if (stream->ctrl.dwMaxVideoFrameSize != buf->bytesused &&
!(stream->cur_format->flags & UVC_FMT_FLAG_COMPRESSED))
buf->error = 1;
}
struct uvc_format *def_format;
struct uvc_format *cur_format;
struct uvc_frame *cur_frame;
- size_t frame_size;
/* Protect access to ctrl, cur_format, cur_frame and hardware video
* probe control.
/* Try to remap memory */
size = vma->vm_end - vma->vm_start;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ /* the "vm_pgoff" is just used in v4l2 to find the
+ * corresponding buffer data structure which is allocated
+ * earlier and it does not mean the offset from the physical
+ * buffer start address as usual. So set it to 0 to pass
+ * the sanity check in vm_iomap_memory().
+ */
+ vma->vm_pgoff = 0;
+
retval = vm_iomap_memory(vma, mem->dma_handle, size);
if (retval) {
dev_err(q->dev, "mmap: remap failed with error %d. ",
#include "cxl.h"
-static struct cxl_sste* find_free_sste(struct cxl_sste *primary_group,
- bool sec_hash,
- struct cxl_sste *secondary_group,
- unsigned int *lru)
+static bool sste_matches(struct cxl_sste *sste, struct copro_slb *slb)
{
- unsigned int i, entry;
- struct cxl_sste *sste, *group = primary_group;
-
- for (i = 0; i < 2; i++) {
- for (entry = 0; entry < 8; entry++) {
- sste = group + entry;
- if (!(be64_to_cpu(sste->esid_data) & SLB_ESID_V))
- return sste;
- }
- if (!sec_hash)
- break;
- group = secondary_group;
+ return ((sste->vsid_data == cpu_to_be64(slb->vsid)) &&
+ (sste->esid_data == cpu_to_be64(slb->esid)));
+}
+
+/*
+ * This finds a free SSTE for the given SLB, or returns NULL if it's already in
+ * the segment table.
+ */
+static struct cxl_sste* find_free_sste(struct cxl_context *ctx,
+ struct copro_slb *slb)
+{
+ struct cxl_sste *primary, *sste, *ret = NULL;
+ unsigned int mask = (ctx->sst_size >> 7) - 1; /* SSTP0[SegTableSize] */
+ unsigned int entry;
+ unsigned int hash;
+
+ if (slb->vsid & SLB_VSID_B_1T)
+ hash = (slb->esid >> SID_SHIFT_1T) & mask;
+ else /* 256M */
+ hash = (slb->esid >> SID_SHIFT) & mask;
+
+ primary = ctx->sstp + (hash << 3);
+
+ for (entry = 0, sste = primary; entry < 8; entry++, sste++) {
+ if (!ret && !(be64_to_cpu(sste->esid_data) & SLB_ESID_V))
+ ret = sste;
+ if (sste_matches(sste, slb))
+ return NULL;
}
+ if (ret)
+ return ret;
+
/* Nothing free, select an entry to cast out */
- if (sec_hash && (*lru & 0x8))
- sste = secondary_group + (*lru & 0x7);
- else
- sste = primary_group + (*lru & 0x7);
- *lru = (*lru + 1) & 0xf;
+ ret = primary + ctx->sst_lru;
+ ctx->sst_lru = (ctx->sst_lru + 1) & 0x7;
- return sste;
+ return ret;
}
static void cxl_load_segment(struct cxl_context *ctx, struct copro_slb *slb)
{
/* mask is the group index, we search primary and secondary here. */
- unsigned int mask = (ctx->sst_size >> 7)-1; /* SSTP0[SegTableSize] */
- bool sec_hash = 1;
struct cxl_sste *sste;
- unsigned int hash;
unsigned long flags;
-
- sec_hash = !!(cxl_p1n_read(ctx->afu, CXL_PSL_SR_An) & CXL_PSL_SR_An_SC);
-
- if (slb->vsid & SLB_VSID_B_1T)
- hash = (slb->esid >> SID_SHIFT_1T) & mask;
- else /* 256M */
- hash = (slb->esid >> SID_SHIFT) & mask;
-
spin_lock_irqsave(&ctx->sste_lock, flags);
- sste = find_free_sste(ctx->sstp + (hash << 3), sec_hash,
- ctx->sstp + ((~hash & mask) << 3), &ctx->sst_lru);
+ sste = find_free_sste(ctx, slb);
+ if (!sste)
+ goto out_unlock;
pr_devel("CXL Populating SST[%li]: %#llx %#llx\n",
sste - ctx->sstp, slb->vsid, slb->esid);
sste->vsid_data = cpu_to_be64(slb->vsid);
sste->esid_data = cpu_to_be64(slb->esid);
+out_unlock:
spin_unlock_irqrestore(&ctx->sste_lock, flags);
}
ctx->elem->haurp = 0; /* disable */
ctx->elem->sdr = cpu_to_be64(mfspr(SPRN_SDR1));
- sr = CXL_PSL_SR_An_SC;
+ sr = 0;
if (ctx->master)
sr |= CXL_PSL_SR_An_MP;
if (mfspr(SPRN_LPCR) & LPCR_TC)
u64 sr;
int rc;
- sr = CXL_PSL_SR_An_SC;
+ sr = 0;
set_endian(sr);
if (ctx->master)
sr |= CXL_PSL_SR_An_MP;
/* Go to known state. Chip may have been power cycled */
if (chip->state == FL_PM_SUSPENDED) {
+ /* Refresh LH28F640BF Partition Config. Register */
+ fixup_LH28F640BF(mtd);
map_write(map, CMD(0xFF), cfi->chips[i].start);
chip->oldstate = chip->state = FL_READY;
wake_up(&chip->wq);
{
struct mtd_part_parser_data ppdata;
struct flash_platform_data *data;
- const struct spi_device_id *id = NULL;
struct m25p *flash;
struct spi_nor *nor;
enum read_mode mode = SPI_NOR_NORMAL;
+ char *flash_name = NULL;
int ret;
data = dev_get_platdata(&spi->dev);
* If that's the case, respect "type" and ignore a "name".
*/
if (data && data->type)
- id = spi_nor_match_id(data->type);
+ flash_name = data->type;
+ else
+ flash_name = spi->modalias;
- /* If we didn't get name from platform, simply use "modalias". */
- if (!id)
- id = spi_get_device_id(spi);
-
- ret = spi_nor_scan(nor, id, mode);
+ ret = spi_nor_scan(nor, flash_name, mode);
if (ret)
return ret;
}
+/*
+ * XXX This needs to be kept in sync with spi_nor_ids. We can't share
+ * it with spi-nor, because if this is built as a module then modpost
+ * won't be able to read it and add appropriate aliases.
+ */
+static const struct spi_device_id m25p_ids[] = {
+ {"at25fs010"}, {"at25fs040"}, {"at25df041a"}, {"at25df321a"},
+ {"at25df641"}, {"at26f004"}, {"at26df081a"}, {"at26df161a"},
+ {"at26df321"}, {"at45db081d"},
+ {"en25f32"}, {"en25p32"}, {"en25q32b"}, {"en25p64"},
+ {"en25q64"}, {"en25qh128"}, {"en25qh256"},
+ {"f25l32pa"},
+ {"mr25h256"}, {"mr25h10"},
+ {"gd25q32"}, {"gd25q64"},
+ {"160s33b"}, {"320s33b"}, {"640s33b"},
+ {"mx25l2005a"}, {"mx25l4005a"}, {"mx25l8005"}, {"mx25l1606e"},
+ {"mx25l3205d"}, {"mx25l3255e"}, {"mx25l6405d"}, {"mx25l12805d"},
+ {"mx25l12855e"},{"mx25l25635e"},{"mx25l25655e"},{"mx66l51235l"},
+ {"mx66l1g55g"},
+ {"n25q064"}, {"n25q128a11"}, {"n25q128a13"}, {"n25q256a"},
+ {"n25q512a"}, {"n25q512ax3"}, {"n25q00"},
+ {"pm25lv512"}, {"pm25lv010"}, {"pm25lq032"},
+ {"s25sl032p"}, {"s25sl064p"}, {"s25fl256s0"}, {"s25fl256s1"},
+ {"s25fl512s"}, {"s70fl01gs"}, {"s25sl12800"}, {"s25sl12801"},
+ {"s25fl129p0"}, {"s25fl129p1"}, {"s25sl004a"}, {"s25sl008a"},
+ {"s25sl016a"}, {"s25sl032a"}, {"s25sl064a"}, {"s25fl008k"},
+ {"s25fl016k"}, {"s25fl064k"},
+ {"sst25vf040b"},{"sst25vf080b"},{"sst25vf016b"},{"sst25vf032b"},
+ {"sst25vf064c"},{"sst25wf512"}, {"sst25wf010"}, {"sst25wf020"},
+ {"sst25wf040"},
+ {"m25p05"}, {"m25p10"}, {"m25p20"}, {"m25p40"},
+ {"m25p80"}, {"m25p16"}, {"m25p32"}, {"m25p64"},
+ {"m25p128"}, {"n25q032"},
+ {"m25p05-nonjedec"}, {"m25p10-nonjedec"}, {"m25p20-nonjedec"},
+ {"m25p40-nonjedec"}, {"m25p80-nonjedec"}, {"m25p16-nonjedec"},
+ {"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"},
+ {"m45pe10"}, {"m45pe80"}, {"m45pe16"},
+ {"m25pe20"}, {"m25pe80"}, {"m25pe16"},
+ {"m25px16"}, {"m25px32"}, {"m25px32-s0"}, {"m25px32-s1"},
+ {"m25px64"},
+ {"w25x10"}, {"w25x20"}, {"w25x40"}, {"w25x80"},
+ {"w25x16"}, {"w25x32"}, {"w25q32"}, {"w25q32dw"},
+ {"w25x64"}, {"w25q64"}, {"w25q128"}, {"w25q80"},
+ {"w25q80bl"}, {"w25q128"}, {"w25q256"}, {"cat25c11"},
+ {"cat25c03"}, {"cat25c09"}, {"cat25c17"}, {"cat25128"},
+ { },
+};
+MODULE_DEVICE_TABLE(spi, m25p_ids);
+
+
static struct spi_driver m25p80_driver = {
.driver = {
.name = "m25p80",
.owner = THIS_MODULE,
},
- .id_table = spi_nor_ids,
+ .id_table = m25p_ids,
.probe = m25p_probe,
.remove = m25p_remove,
if (!info) {
dev_err(dev, "Unable to configure elm - device not probed?\n");
- return -ENODEV;
+ return -EPROBE_DEFER;
}
/* ELM cannot detect ECC errors for chunks > 1KB */
if (ecc_step_size > ((ELM_ECC_SIZE + 1) / 2)) {
/* iterate the subnodes. */
for_each_available_child_of_node(dev->of_node, np) {
- const struct spi_device_id *id;
char modalias[40];
/* skip the holes */
if (of_modalias_node(np, modalias, sizeof(modalias)) < 0)
goto map_failed;
- id = spi_nor_match_id(modalias);
- if (!id)
- goto map_failed;
-
ret = of_property_read_u32(np, "spi-max-frequency",
&q->clk_rate);
if (ret < 0)
/* set the chip address for READID */
fsl_qspi_set_base_addr(q, nor);
- ret = spi_nor_scan(nor, id, SPI_NOR_QUAD);
+ ret = spi_nor_scan(nor, modalias, SPI_NOR_QUAD);
if (ret)
goto map_failed;
#define JEDEC_MFR(_jedec_id) ((_jedec_id) >> 16)
+static const struct spi_device_id *spi_nor_match_id(const char *name);
+
/*
* Read the status register, returning its value in the location
* Return the status register value.
* more nor chips. This current list focusses on newer chips, which
* have been converging on command sets which including JEDEC ID.
*/
-const struct spi_device_id spi_nor_ids[] = {
+static const struct spi_device_id spi_nor_ids[] = {
/* Atmel -- some are (confusingly) marketed as "DataFlash" */
{ "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K) },
{ "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) },
{ "cat25128", CAT25_INFO(2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
{ },
};
-EXPORT_SYMBOL_GPL(spi_nor_ids);
static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor)
{
return 0;
}
-int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,
- enum read_mode mode)
+int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
{
+ const struct spi_device_id *id = NULL;
struct flash_info *info;
struct device *dev = nor->dev;
struct mtd_info *mtd = nor->mtd;
if (ret)
return ret;
+ id = spi_nor_match_id(name);
+ if (!id)
+ return -ENOENT;
+
info = (void *)id->driver_data;
if (info->jedec_id) {
}
EXPORT_SYMBOL_GPL(spi_nor_scan);
-const struct spi_device_id *spi_nor_match_id(char *name)
+static const struct spi_device_id *spi_nor_match_id(const char *name)
{
const struct spi_device_id *id = spi_nor_ids;
}
return NULL;
}
-EXPORT_SYMBOL_GPL(spi_nor_match_id);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Huang Shijie <shijie8@gmail.com>");
config MACVTAP
tristate "MAC-VLAN based tap driver"
depends on MACVLAN
+ depends on INET
help
This adds a specialized tap character device driver that is based
on the MAC-VLAN network interface, called macvtap. A macvtap device
config TUN
tristate "Universal TUN/TAP device driver support"
+ depends on INET
select CRC32
---help---
TUN/TAP provides packet reception and transmission for user space
}
struct dsa_switch_driver mv88e6171_switch_driver = {
- .tag_protocol = DSA_TAG_PROTO_DSA,
+ .tag_protocol = DSA_TAG_PROTO_EDSA,
.priv_size = sizeof(struct mv88e6xxx_priv_state),
.probe = mv88e6171_probe,
.setup = mv88e6171_setup,
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct xgbe_hw_if *hw_if = &pdata->hw_if;
- unsigned int rxcsum, rxvlan, rxvlan_filter;
+ netdev_features_t rxcsum, rxvlan, rxvlan_filter;
rxcsum = pdata->netdev_features & NETIF_F_RXCSUM;
rxvlan = pdata->netdev_features & NETIF_F_HW_VLAN_CTAG_RX;
struct skb_shared_hwtstamps *hwtstamps;
unsigned int incomplete, error, context_next, context;
unsigned int len, put_len, max_len;
- int received = 0;
+ unsigned int received = 0;
+ int packet_count = 0;
DBGPR("-->xgbe_rx_poll: budget=%d\n", budget);
rdata = XGBE_GET_DESC_DATA(ring, ring->cur);
packet = &ring->packet_data;
- while (received < budget) {
+ while (packet_count < budget) {
DBGPR(" cur = %d\n", ring->cur);
/* First time in loop see if we need to restore state */
if (packet->errors)
DBGPR("Error in received packet\n");
dev_kfree_skb(skb);
- continue;
+ goto next_packet;
}
if (!context) {
}
dev_kfree_skb(skb);
- continue;
+ goto next_packet;
}
memcpy(skb_tail_pointer(skb), rdata->skb->data,
put_len);
/* Stray Context Descriptor? */
if (!skb)
- continue;
+ goto next_packet;
/* Be sure we don't exceed the configured MTU */
max_len = netdev->mtu + ETH_HLEN;
if (skb->len > max_len) {
DBGPR("packet length exceeds configured MTU\n");
dev_kfree_skb(skb);
- continue;
+ goto next_packet;
}
#ifdef XGMAC_ENABLE_RX_PKT_DUMP
netdev->last_rx = jiffies;
napi_gro_receive(&pdata->napi, skb);
+
+next_packet:
+ packet_count++;
}
/* Check if we need to save state before leaving */
rdata->state.error = error;
}
- DBGPR("<--xgbe_rx_poll: received = %d\n", received);
+ DBGPR("<--xgbe_rx_poll: packet_count = %d\n", packet_count);
- return received;
+ return packet_count;
}
static int xgbe_poll(struct napi_struct *napi, int budget)
{
struct net_device *ndev = p->ndev;
u32 data;
- int i;
+ int i = 0;
xgene_enet_wr_diag_csr(p, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0);
- for (i = 0; i < 10 && data != ~0U ; i++) {
+ do {
usleep_range(100, 110);
data = xgene_enet_rd_diag_csr(p, ENET_BLOCK_MEM_RDY_ADDR);
- }
+ if (data == ~0U)
+ return 0;
+ } while (++i < 10);
- if (data != ~0U) {
- netdev_err(ndev, "Failed to release memory from shutdown\n");
- return -ENODEV;
- }
-
- return 0;
+ netdev_err(ndev, "Failed to release memory from shutdown\n");
+ return -ENODEV;
}
static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *p)
/* Enable NAPI */
napi_enable(&priv->napi);
+ /* Enable RX interrupt and TX ring full interrupt */
+ intrl2_0_mask_clear(priv, INTRL2_0_RDMA_MBDONE | INTRL2_0_TX_RING_FULL);
+
phy_start(priv->phydev);
/* Enable TX interrupts for the 32 TXQs */
if (ret)
goto out_free_rx_ring;
- /* Enable RX interrupt and TX ring full interrupt */
- intrl2_0_mask_clear(priv, INTRL2_0_RDMA_MBDONE | INTRL2_0_TX_RING_FULL);
-
/* Turn on TDMA */
ret = tdma_enable_set(priv, 1);
if (ret)
if (!netif_running(dev))
return 0;
+ umac_reset(priv);
+
/* We may have been suspended and never received a WOL event that
* would turn off MPD detection, take care of that now
*/
netif_device_attach(dev);
- /* Enable RX interrupt and TX ring full interrupt */
- intrl2_0_mask_clear(priv, INTRL2_0_RDMA_MBDONE | INTRL2_0_TX_RING_FULL);
-
/* RX pipe enable */
topctrl_writel(priv, 0, RX_FLUSH_CNTL);
if (l5_cid >= MAX_CM_SK_TBL_SZ)
break;
- rcu_read_lock();
if (!rcu_access_pointer(cp->ulp_ops[CNIC_ULP_L4])) {
rc = -ENODEV;
- rcu_read_unlock();
break;
}
csk = &cp->csk_tbl[l5_cid];
}
}
csk_put(csk);
- rcu_read_unlock();
rc = 0;
}
}
cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL);
mutex_lock(&cnic_lock);
- if (rcu_dereference(cp->ulp_ops[ulp_type])) {
+ if (rcu_access_pointer(cp->ulp_ops[ulp_type])) {
RCU_INIT_POINTER(cp->ulp_ops[ulp_type], NULL);
cnic_put(dev);
} else {
dcb->dcb_version = FW_PORT_DCB_VER_AUTO;
}
+static void cxgb4_dcb_cleanup_apps(struct net_device *dev)
+{
+ struct port_info *pi = netdev2pinfo(dev);
+ struct adapter *adap = pi->adapter;
+ struct port_dcb_info *dcb = &pi->dcb;
+ struct dcb_app app;
+ int i, err;
+
+ /* zero priority implies remove */
+ app.priority = 0;
+
+ for (i = 0; i < CXGB4_MAX_DCBX_APP_SUPPORTED; i++) {
+ /* Check if app list is exhausted */
+ if (!dcb->app_priority[i].protocolid)
+ break;
+
+ app.protocol = dcb->app_priority[i].protocolid;
+
+ if (dcb->dcb_version == FW_PORT_DCB_VER_IEEE) {
+ app.selector = dcb->app_priority[i].sel_field + 1;
+ err = dcb_ieee_setapp(dev, &app);
+ } else {
+ app.selector = !!(dcb->app_priority[i].sel_field);
+ err = dcb_setapp(dev, &app);
+ }
+
+ if (err) {
+ dev_err(adap->pdev_dev,
+ "Failed DCB Clear %s Application Priority: sel=%d, prot=%d, , err=%d\n",
+ dcb_ver_array[dcb->dcb_version], app.selector,
+ app.protocol, -err);
+ break;
+ }
+ }
+}
+
/* Finite State machine for Data Center Bridging.
*/
void cxgb4_dcb_state_fsm(struct net_device *dev,
/* we're going to use Host DCB */
dcb->state = CXGB4_DCB_STATE_HOST;
dcb->supported = CXGB4_DCBX_HOST_SUPPORT;
- dcb->enabled = 1;
break;
}
* state. We need to reset back to a ground state
* of incomplete.
*/
+ cxgb4_dcb_cleanup_apps(dev);
cxgb4_dcb_state_init(dev);
dcb->state = CXGB4_DCB_STATE_FW_INCOMPLETE;
dcb->supported = CXGB4_DCBX_FW_SUPPORT;
{
struct port_info *pi = netdev2pinfo(dev);
+ /* If DCBx is host-managed, dcb is enabled by outside lldp agents */
+ if (pi->dcb.state == CXGB4_DCB_STATE_HOST) {
+ pi->dcb.enabled = enabled;
+ return 0;
+ }
+
/* Firmware doesn't provide any mechanism to control the DCB state.
*/
if (enabled != (pi->dcb.state == CXGB4_DCB_STATE_FW_ALLSYNCED))
/* Return whether IEEE Data Center Bridging has been negotiated.
*/
-static inline int cxgb4_ieee_negotiation_complete(struct net_device *dev)
+static inline int
+cxgb4_ieee_negotiation_complete(struct net_device *dev,
+ enum cxgb4_dcb_fw_msgs dcb_subtype)
{
struct port_info *pi = netdev2pinfo(dev);
struct port_dcb_info *dcb = &pi->dcb;
+ if (dcb_subtype && !(dcb->msgs & dcb_subtype))
+ return 0;
+
return (dcb->state == CXGB4_DCB_STATE_FW_ALLSYNCED &&
(dcb->supported & DCB_CAP_DCBX_VER_IEEE));
}
{
int prio;
- if (!cxgb4_ieee_negotiation_complete(dev))
+ if (!cxgb4_ieee_negotiation_complete(dev, CXGB4_DCB_FW_APP_ID))
return -EINVAL;
if (!(app->selector && app->protocol))
return -EINVAL;
{
int ret;
- if (!cxgb4_ieee_negotiation_complete(dev))
+ if (!cxgb4_ieee_negotiation_complete(dev, CXGB4_DCB_FW_APP_ID))
return -EINVAL;
if (!(app->selector && app->protocol))
return -EINVAL;
#ifdef CONFIG_CHELSIO_T4_DCB
struct port_info *pi = netdev_priv(dev);
- return pi->dcb.state == CXGB4_DCB_STATE_FW_ALLSYNCED;
+ if (!pi->dcb.enabled)
+ return 0;
+
+ return ((pi->dcb.state == CXGB4_DCB_STATE_FW_ALLSYNCED) ||
+ (pi->dcb.state == CXGB4_DCB_STATE_HOST));
#else
return 0;
#endif
spin_lock_init(&adapter->stats_lock);
spin_lock_init(&adapter->tid_release_lock);
+ spin_lock_init(&adapter->win0_lock);
INIT_WORK(&adapter->tid_release_task, process_tid_release_list);
INIT_WORK(&adapter->db_full_task, process_db_full);
CH_DEVICE(0x480d), /* T480-cr */
CH_DEVICE(0x480e), /* T440-lp-cr */
CH_DEVICE(0x4880),
- CH_DEVICE(0x4880),
- CH_DEVICE(0x4880),
- CH_DEVICE(0x4880),
- CH_DEVICE(0x4880),
- CH_DEVICE(0x4880),
- CH_DEVICE(0x4880),
- CH_DEVICE(0x4880),
- CH_DEVICE(0x4880),
+ CH_DEVICE(0x4881),
+ CH_DEVICE(0x4882),
+ CH_DEVICE(0x4883),
+ CH_DEVICE(0x4884),
+ CH_DEVICE(0x4885),
+ CH_DEVICE(0x4886),
+ CH_DEVICE(0x4887),
+ CH_DEVICE(0x4888),
CH_DEVICE(0x5801), /* T520-cr */
CH_DEVICE(0x5802), /* T522-cr */
CH_DEVICE(0x5803), /* T540-cr */
int i;
enic_rfs_timer_stop(enic);
- spin_lock(&enic->rfs_h.lock);
+ spin_lock_bh(&enic->rfs_h.lock);
enic->rfs_h.free = 0;
for (i = 0; i < (1 << ENIC_RFS_FLW_BITSHIFT); i++) {
struct hlist_head *hhead;
kfree(n);
}
}
- spin_unlock(&enic->rfs_h.lock);
+ spin_unlock_bh(&enic->rfs_h.lock);
}
struct enic_rfs_fltr_node *htbl_fltr_search(struct enic *enic, u16 fltr_id)
bool res;
int j;
- spin_lock(&enic->rfs_h.lock);
+ spin_lock_bh(&enic->rfs_h.lock);
for (j = 0; j < ENIC_CLSF_EXPIRE_COUNT; j++) {
struct hlist_head *hhead;
struct hlist_node *tmp;
}
}
}
- spin_unlock(&enic->rfs_h.lock);
+ spin_unlock_bh(&enic->rfs_h.lock);
mod_timer(&enic->rfs_h.rfs_may_expire, jiffies + HZ/4);
}
return -EPROTONOSUPPORT;
tbl_idx = skb_get_hash_raw(skb) & ENIC_RFS_FLW_MASK;
- spin_lock(&enic->rfs_h.lock);
+ spin_lock_bh(&enic->rfs_h.lock);
n = htbl_key_search(&enic->rfs_h.ht_head[tbl_idx], &keys);
if (n) { /* entry already present */
}
ret_unlock:
- spin_unlock(&enic->rfs_h.lock);
+ spin_unlock_bh(&enic->rfs_h.lock);
return res;
}
enic_dev_disable(enic);
- local_bh_disable();
for (i = 0; i < enic->rq_count; i++) {
napi_disable(&enic->napi[i]);
+ local_bh_disable();
while (!enic_poll_lock_napi(&enic->rq[i]))
mdelay(1);
+ local_bh_enable();
}
- local_bh_enable();
netif_carrier_off(netdev);
netif_tx_disable(netdev);
complete(&fep->mdio_done);
}
- fec_ptp_check_pps_event(fep);
+ if (fep->ptp_clock)
+ fec_ptp_check_pps_event(fep);
return ret;
}
FC(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD disable */
}
+ /* Restore multicast and promiscuous settings */
+ set_multicast_list(dev);
+
/*
* Enable interrupts we wish to service.
*/
if (fep->phydev->duplex)
S16(sccp, scc_psmr, SCC_PSMR_LPB | SCC_PSMR_FDE);
+ /* Restore multicast and promiscuous settings */
+ set_multicast_list(dev);
+
S32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
}
NETIF_F_HW_CSUM |
NETIF_F_SG);
- netdev->priv_flags |= IFF_UNICAST_FLT;
+ /* Do not set IFF_UNICAST_FLT for VMWare's 82545EM */
+ if (hw->device_id != E1000_DEV_ID_82545EM_COPPER ||
+ hw->subsystem_vendor_id != PCI_VENDOR_ID_VMWARE)
+ netdev->priv_flags |= IFF_UNICAST_FLT;
adapter->en_mng_pt = e1000_enable_mng_pass_thru(hw);
I40E_GL_MDET_TX_PF_NUM_SHIFT;
u8 vf_num = (reg & I40E_GL_MDET_TX_VF_NUM_MASK) >>
I40E_GL_MDET_TX_VF_NUM_SHIFT;
- u8 event = (reg & I40E_GL_MDET_TX_EVENT_SHIFT) >>
+ u8 event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >>
I40E_GL_MDET_TX_EVENT_SHIFT;
u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >>
I40E_GL_MDET_TX_QUEUE_SHIFT;
if (reg & I40E_GL_MDET_RX_VALID_MASK) {
u8 func = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >>
I40E_GL_MDET_RX_FUNCTION_SHIFT;
- u8 event = (reg & I40E_GL_MDET_RX_EVENT_SHIFT) >>
+ u8 event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >>
I40E_GL_MDET_RX_EVENT_SHIFT;
u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >>
I40E_GL_MDET_RX_QUEUE_SHIFT;
if (unlikely(page_to_nid(page) != numa_node_id()))
return false;
+ if (unlikely(page->pfmemalloc))
+ return false;
+
#if (PAGE_SIZE < 8192)
/* if we are only owner of page we can reuse it */
if (unlikely(page_count(page) != 1))
memcpy(__skb_put(skb, size), va, ALIGN(size, sizeof(long)));
/* we can reuse buffer as-is, just make sure it is local */
- if (likely(page_to_nid(page) == numa_node_id()))
+ if (likely((page_to_nid(page) == numa_node_id()) &&
+ !page->pfmemalloc))
return true;
/* this page cannot be reused so discard it */
if (old == advertised)
return err;
/* this sets the link speed and restarts auto-neg */
+ while (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
+ usleep_range(1000, 2000);
+
hw->mac.autotry_restart = true;
err = hw->mac.ops.setup_link(hw, advertised, true);
if (err) {
e_info(probe, "setup link failed with code %d\n", err);
hw->mac.ops.setup_link(hw, old, true);
}
+ clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state);
} else {
/* in this case we currently only support 10Gb/FULL */
u32 speed = ethtool_cmd_speed(ecmd);
IXGBE_CB(skb)->page_released = false;
}
dev_kfree_skb(skb);
+ rx_buffer->skb = NULL;
}
- rx_buffer->skb = NULL;
if (rx_buffer->dma)
dma_unmap_page(dev, rx_buffer->dma,
ixgbe_rx_pg_size(rx_ring),
* whether LSO is used */
tx_desc->ctrl.srcrb_flags = priv->ctrl_flags;
if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
- tx_desc->ctrl.srcrb_flags |= cpu_to_be32(MLX4_WQE_CTRL_IP_CSUM |
- MLX4_WQE_CTRL_TCP_UDP_CSUM);
+ if (!skb->encapsulation)
+ tx_desc->ctrl.srcrb_flags |= cpu_to_be32(MLX4_WQE_CTRL_IP_CSUM |
+ MLX4_WQE_CTRL_TCP_UDP_CSUM);
+ else
+ tx_desc->ctrl.srcrb_flags |= cpu_to_be32(MLX4_WQE_CTRL_IP_CSUM);
ring->tx_csum++;
}
pr_cont("\n");
}
}
+ synchronize_irq(eq->irq);
mlx4_mtt_cleanup(dev, &eq->mtt);
for (i = 0; i < npages; ++i)
cur->ib.dst_gid_msk);
break;
+ case MLX4_NET_TRANS_RULE_ID_VXLAN:
+ len += snprintf(buf + len, BUF_SIZE - len,
+ "VNID = %d ", be32_to_cpu(cur->vxlan.vni));
+ break;
case MLX4_NET_TRANS_RULE_ID_IPV6:
break;
if (err)
mlx5_core_warn(dev, "failed to destroy a previously created eq: eqn %d\n",
eq->eqn);
+ synchronize_irq(table->msix_arr[eq->irqn].vector);
mlx5_buf_free(dev, &eq->buf);
return err;
unsigned short dma_flags;
int i = 0;
- EFX_BUG_ON_PARANOID(tx_queue->write_count > tx_queue->insert_count);
-
if (skb_shinfo(skb)->gso_size)
return efx_enqueue_skb_tso(tx_queue, skb);
/* Find the packet protocol and sanity-check it */
state.protocol = efx_tso_check_protocol(skb);
- EFX_BUG_ON_PARANOID(tx_queue->write_count > tx_queue->insert_count);
-
rc = tso_start(&state, efx, skb);
if (rc)
goto mem_err;
#include <linux/workqueue.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/of_gpio.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
{},
};
MODULE_DEVICE_TABLE(of, smc91x_match);
+
+/**
+ * of_try_set_control_gpio - configure a gpio if it exists
+ */
+static int try_toggle_control_gpio(struct device *dev,
+ struct gpio_desc **desc,
+ const char *name, int index,
+ int value, unsigned int nsdelay)
+{
+ struct gpio_desc *gpio = *desc;
+ int res;
+
+ gpio = devm_gpiod_get_index(dev, name, index);
+ if (IS_ERR(gpio)) {
+ if (PTR_ERR(gpio) == -ENOENT) {
+ *desc = NULL;
+ return 0;
+ }
+
+ return PTR_ERR(gpio);
+ }
+ res = gpiod_direction_output(gpio, !value);
+ if (res) {
+ dev_err(dev, "unable to toggle gpio %s: %i\n", name, res);
+ devm_gpiod_put(dev, gpio);
+ gpio = NULL;
+ return res;
+ }
+ if (nsdelay)
+ usleep_range(nsdelay, 2 * nsdelay);
+ gpiod_set_value_cansleep(gpio, value);
+ *desc = gpio;
+
+ return 0;
+}
#endif
/*
struct device_node *np = pdev->dev.of_node;
u32 val;
+ /* Optional pwrdwn GPIO configured? */
+ ret = try_toggle_control_gpio(&pdev->dev, &lp->power_gpio,
+ "power", 0, 0, 100);
+ if (ret)
+ return ret;
+
+ /*
+ * Optional reset GPIO configured? Minimum 100 ns reset needed
+ * according to LAN91C96 datasheet page 14.
+ */
+ ret = try_toggle_control_gpio(&pdev->dev, &lp->reset_gpio,
+ "reset", 0, 0, 100);
+ if (ret)
+ return ret;
+
+ /*
+ * Need to wait for optional EEPROM to load, max 750 us according
+ * to LAN91C96 datasheet page 55.
+ */
+ if (lp->reset_gpio)
+ usleep_range(750, 1000);
+
/* Combination of IO widths supported, default to 16-bit */
if (!of_property_read_u32(np, "reg-io-width", &val)) {
if (val & 1)
struct sk_buff *pending_tx_skb;
struct tasklet_struct tx_task;
+ struct gpio_desc *power_gpio;
+ struct gpio_desc *reset_gpio;
+
/* version/revision of the SMC91x chip */
int version;
static void stmmac_default_data(void)
{
memset(&plat_dat, 0, sizeof(struct plat_stmmacenet_data));
+
plat_dat.bus_id = 1;
plat_dat.phy_addr = 0;
plat_dat.interface = PHY_INTERFACE_MODE_GMII;
dma_cfg.pbl = 32;
dma_cfg.burst_len = DMA_AXI_BLEN_256;
plat_dat.dma_cfg = &dma_cfg;
+
+ /* Set default value for multicast hash bins */
+ plat_dat.multicast_filter_bins = HASH_TABLE_SIZE;
+
+ /* Set default value for unicast filter entries */
+ plat_dat.unicast_filter_entries = 1;
}
/**
if (enable) {
unsigned long timeout = jiffies + HZ;
- /* Disable Learn for all ports */
- for (i = 0; i < priv->data.slaves; i++) {
+ /* Disable Learn for all ports (host is port 0 and slaves are port 1 and up */
+ for (i = 0; i <= priv->data.slaves; i++) {
cpsw_ale_control_set(ale, i,
ALE_PORT_NOLEARN, 1);
cpsw_ale_control_set(ale, i,
cpsw_ale_control_set(ale, 0, ALE_P0_UNI_FLOOD, 1);
dev_dbg(&ndev->dev, "promiscuity enabled\n");
} else {
- /* Flood All Unicast Packets to Host port */
+ /* Don't Flood All Unicast Packets to Host port */
cpsw_ale_control_set(ale, 0, ALE_P0_UNI_FLOOD, 0);
- /* Enable Learn for all ports */
- for (i = 0; i < priv->data.slaves; i++) {
+ /* Enable Learn for all ports (host is port 0 and slaves are port 1 and up */
+ for (i = 0; i <= priv->data.slaves; i++) {
cpsw_ale_control_set(ale, i,
ALE_PORT_NOLEARN, 0);
cpsw_ale_control_set(ale, i,
if (ndev->flags & IFF_PROMISC) {
/* Enable promiscuous mode */
cpsw_set_promiscious(ndev, true);
+ cpsw_ale_set_allmulti(priv->ale, IFF_ALLMULTI);
return;
} else {
/* Disable promiscuous mode */
cpsw_set_promiscious(ndev, false);
}
+ /* Restore allmulti on vlans if necessary */
+ cpsw_ale_set_allmulti(priv->ale, priv->ndev->flags & IFF_ALLMULTI);
+
/* Clear all mcast from ALE */
cpsw_ale_flush_multicast(priv->ale, ALE_ALL_PORTS << priv->host_port);
const int port = priv->host_port;
u32 reg;
int i;
+ int unreg_mcast_mask;
reg = (priv->version == CPSW_VERSION_1) ? CPSW1_PORT_VLAN :
CPSW2_PORT_VLAN;
for (i = 0; i < priv->data.slaves; i++)
slave_write(priv->slaves + i, vlan, reg);
+ if (priv->ndev->flags & IFF_ALLMULTI)
+ unreg_mcast_mask = ALE_ALL_PORTS;
+ else
+ unreg_mcast_mask = ALE_PORT_1 | ALE_PORT_2;
+
cpsw_ale_add_vlan(priv->ale, vlan, ALE_ALL_PORTS << port,
ALE_ALL_PORTS << port, ALE_ALL_PORTS << port,
- (ALE_PORT_1 | ALE_PORT_2) << port);
+ unreg_mcast_mask << port);
}
static void cpsw_init_host_port(struct cpsw_priv *priv)
unsigned short vid)
{
int ret;
+ int unreg_mcast_mask;
+
+ if (priv->ndev->flags & IFF_ALLMULTI)
+ unreg_mcast_mask = ALE_ALL_PORTS;
+ else
+ unreg_mcast_mask = ALE_PORT_1 | ALE_PORT_2;
ret = cpsw_ale_add_vlan(priv->ale, vid,
ALE_ALL_PORTS << priv->host_port,
0, ALE_ALL_PORTS << priv->host_port,
- (ALE_PORT_1 | ALE_PORT_2) << priv->host_port);
+ unreg_mcast_mask << priv->host_port);
if (ret != 0)
return ret;
parp = of_get_property(slave_node, "phy_id", &lenp);
if ((parp == NULL) || (lenp != (sizeof(void *) * 2))) {
dev_err(&pdev->dev, "Missing slave[%d] phy_id property\n", i);
- return -EINVAL;
+ goto no_phy_slave;
}
mdio_node = of_find_node_by_phandle(be32_to_cpup(parp));
phyid = be32_to_cpup(parp+1);
snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
PHY_ID_FMT, mdio->name, phyid);
+ slave_data->phy_if = of_get_phy_mode(slave_node);
+ if (slave_data->phy_if < 0) {
+ dev_err(&pdev->dev, "Missing or malformed slave[%d] phy-mode property\n",
+ i);
+ return slave_data->phy_if;
+ }
+
+no_phy_slave:
mac_addr = of_get_mac_address(slave_node);
if (mac_addr) {
memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN);
return ret;
}
}
-
- slave_data->phy_if = of_get_phy_mode(slave_node);
- if (slave_data->phy_if < 0) {
- dev_err(&pdev->dev, "Missing or malformed slave[%d] phy-mode property\n",
- i);
- return slave_data->phy_if;
- }
-
if (data->dual_emac) {
if (of_property_read_u32(slave_node, "dual_emac_res_vlan",
&prop)) {
return 0;
}
+void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti)
+{
+ u32 ale_entry[ALE_ENTRY_WORDS];
+ int type, idx;
+ int unreg_mcast = 0;
+
+ /* Only bother doing the work if the setting is actually changing */
+ if (ale->allmulti == allmulti)
+ return;
+
+ /* Remember the new setting to check against next time */
+ ale->allmulti = allmulti;
+
+ for (idx = 0; idx < ale->params.ale_entries; idx++) {
+ cpsw_ale_read(ale, idx, ale_entry);
+ type = cpsw_ale_get_entry_type(ale_entry);
+ if (type != ALE_TYPE_VLAN)
+ continue;
+
+ unreg_mcast = cpsw_ale_get_vlan_unreg_mcast(ale_entry);
+ if (allmulti)
+ unreg_mcast |= 1;
+ else
+ unreg_mcast &= ~1;
+ cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast);
+ cpsw_ale_write(ale, idx, ale_entry);
+ }
+}
+
struct ale_control_info {
const char *name;
int offset, port_offset;
struct cpsw_ale_params params;
struct timer_list timer;
unsigned long ageout;
+ int allmulti;
};
enum cpsw_ale_control {
int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
int reg_mcast, int unreg_mcast);
int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port);
+void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti);
int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control);
int cpsw_ale_control_set(struct cpsw_ale *ale, int port,
do_send:
/* Start filling in the page buffers with the rndis hdr */
rndis_msg->msg_len += rndis_msg_size;
+ packet->total_data_buflen = rndis_msg->msg_len;
packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size,
skb, &packet->page_buf[0]);
struct sk_buff *skb;
struct sk_buff_head list;
- skb_queue_head_init(&list);
+ __skb_queue_head_init(&list);
spin_lock_bh(&port->bc_queue.lock);
skb_queue_splice_tail_init(&port->bc_queue, &list);
{
struct macvlan_port *port = macvlan_port_get_rtnl(dev);
- cancel_work_sync(&port->bc_work);
dev->priv_flags &= ~IFF_MACVLAN_PORT;
netdev_rx_handler_unregister(dev);
+
+ /* After this point, no packet can schedule bc_work anymore,
+ * but we need to cancel it and purge left skbs if any.
+ */
+ cancel_work_sync(&port->bc_work);
+ __skb_queue_purge(&port->bc_queue);
+
kfree_rcu(port, rcu);
}
#include <linux/idr.h>
#include <linux/fs.h>
+#include <net/ipv6.h>
#include <net/net_namespace.h>
#include <net/rtnetlink.h>
#include <net/sock.h>
static const struct proto_ops macvtap_socket_ops;
#define TUN_OFFLOADS (NETIF_F_HW_CSUM | NETIF_F_TSO_ECN | NETIF_F_TSO | \
- NETIF_F_TSO6 | NETIF_F_UFO)
+ NETIF_F_TSO6)
#define RX_OFFLOADS (NETIF_F_GRO | NETIF_F_LRO)
#define TAP_FEATURES (NETIF_F_GSO | NETIF_F_SG)
gso_type = SKB_GSO_TCPV6;
break;
case VIRTIO_NET_HDR_GSO_UDP:
+ pr_warn_once("macvtap: %s: using disabled UFO feature; please fix this program\n",
+ current->comm);
gso_type = SKB_GSO_UDP;
+ if (skb->protocol == htons(ETH_P_IPV6))
+ ipv6_proxy_select_ident(skb);
break;
default:
return -EINVAL;
vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
else if (sinfo->gso_type & SKB_GSO_TCPV6)
vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
- else if (sinfo->gso_type & SKB_GSO_UDP)
- vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP;
else
BUG();
if (sinfo->gso_type & SKB_GSO_TCP_ECN)
if (arg & TUN_F_TSO6)
feature_mask |= NETIF_F_TSO6;
}
-
- if (arg & TUN_F_UFO)
- feature_mask |= NETIF_F_UFO;
}
/* tun/tap driver inverts the usage for TSO offloads, where
* When user space turns off TSO, we turn off GSO/LRO so that
* user-space will not receive TSO frames.
*/
- if (feature_mask & (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_UFO))
+ if (feature_mask & (NETIF_F_TSO | NETIF_F_TSO6))
features |= RX_OFFLOADS;
else
features &= ~RX_OFFLOADS;
case TUNSETOFFLOAD:
/* let the user check for future flags */
if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 |
- TUN_F_TSO_ECN | TUN_F_UFO))
+ TUN_F_TSO_ECN))
return -EINVAL;
rtnl_lock();
#define MII_M1011_PHY_SCR 0x10
#define MII_M1011_PHY_SCR_AUTO_CROSS 0x0060
+#define MII_M1145_PHY_EXT_SR 0x1b
#define MII_M1145_PHY_EXT_CR 0x14
#define MII_M1145_RGMII_RX_DELAY 0x0080
#define MII_M1145_RGMII_TX_DELAY 0x0002
+#define MII_M1145_HWCFG_MODE_SGMII_NO_CLK 0x4
+#define MII_M1145_HWCFG_MODE_MASK 0xf
+#define MII_M1145_HWCFG_FIBER_COPPER_AUTO 0x8000
+
#define MII_M1111_PHY_LED_CONTROL 0x18
#define MII_M1111_PHY_LED_DIRECT 0x4100
#define MII_M1111_PHY_LED_COMBINE 0x411c
}
}
+ if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
+ int temp = phy_read(phydev, MII_M1145_PHY_EXT_SR);
+ if (temp < 0)
+ return temp;
+
+ temp &= ~MII_M1145_HWCFG_MODE_MASK;
+ temp |= MII_M1145_HWCFG_MODE_SGMII_NO_CLK;
+ temp |= MII_M1145_HWCFG_FIBER_COPPER_AUTO;
+
+ err = phy_write(phydev, MII_M1145_PHY_EXT_SR, temp);
+ if (err < 0)
+ return err;
+ }
+
err = marvell_of_reg_init(phydev);
if (err < 0)
return err;
#include <linux/nsproxy.h>
#include <linux/virtio_net.h>
#include <linux/rcupdate.h>
+#include <net/ipv6.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/rtnetlink.h>
struct net_device *dev;
netdev_features_t set_features;
#define TUN_USER_FEATURES (NETIF_F_HW_CSUM|NETIF_F_TSO_ECN|NETIF_F_TSO| \
- NETIF_F_TSO6|NETIF_F_UFO)
+ NETIF_F_TSO6)
int vnet_hdr_sz;
int sndbuf;
break;
}
+ skb_reset_network_header(skb);
+
if (gso.gso_type != VIRTIO_NET_HDR_GSO_NONE) {
pr_debug("GSO!\n");
switch (gso.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
break;
case VIRTIO_NET_HDR_GSO_UDP:
+ {
+ static bool warned;
+
+ if (!warned) {
+ warned = true;
+ netdev_warn(tun->dev,
+ "%s: using disabled UFO feature; please fix this program\n",
+ current->comm);
+ }
skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
+ if (skb->protocol == htons(ETH_P_IPV6))
+ ipv6_proxy_select_ident(skb);
break;
+ }
default:
tun->dev->stats.rx_frame_errors++;
kfree_skb(skb);
skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
}
- skb_reset_network_header(skb);
skb_probe_transport_header(skb, 0);
rxhash = skb_get_hash(skb);
gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
else if (sinfo->gso_type & SKB_GSO_TCPV6)
gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
- else if (sinfo->gso_type & SKB_GSO_UDP)
- gso.gso_type = VIRTIO_NET_HDR_GSO_UDP;
else {
pr_err("unexpected GSO type: "
"0x%x, gso_size %d, hdr_len %d\n",
features |= NETIF_F_TSO6;
arg &= ~(TUN_F_TSO4|TUN_F_TSO6);
}
-
- if (arg & TUN_F_UFO) {
- features |= NETIF_F_UFO;
- arg &= ~TUN_F_UFO;
- }
}
/* This gives the user a way to test for new features in future by
{
struct usbnet *dev = netdev_priv(net);
struct sockaddr *addr = p;
+ int ret;
if (netif_running(net))
return -EBUSY;
memcpy(net->dev_addr, addr->sa_data, ETH_ALEN);
/* Set the MAC address */
- return ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN,
+ ret = ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN,
ETH_ALEN, net->dev_addr);
+ if (ret < 0)
+ return ret;
+
+ return 0;
}
static const struct net_device_ops ax88179_netdev_ops = {
0xa6, 0x07, 0xc0, 0xff, 0xcb, 0x7e, 0x39, 0x2a,
};
+static void usbnet_cdc_update_filter(struct usbnet *dev)
+{
+ struct cdc_state *info = (void *) &dev->data;
+ struct usb_interface *intf = info->control;
+
+ u16 cdc_filter =
+ USB_CDC_PACKET_TYPE_ALL_MULTICAST | USB_CDC_PACKET_TYPE_DIRECTED |
+ USB_CDC_PACKET_TYPE_BROADCAST;
+
+ if (dev->net->flags & IFF_PROMISC)
+ cdc_filter |= USB_CDC_PACKET_TYPE_PROMISCUOUS;
+
+ /* FIXME cdc-ether has some multicast code too, though it complains
+ * in routine cases. info->ether describes the multicast support.
+ * Implement that here, manipulating the cdc filter as needed.
+ */
+
+ usb_control_msg(dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ USB_CDC_SET_ETHERNET_PACKET_FILTER,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ cdc_filter,
+ intf->cur_altsetting->desc.bInterfaceNumber,
+ NULL,
+ 0,
+ USB_CTRL_SET_TIMEOUT
+ );
+}
+
/* probes control interface, claims data interface, collects the bulk
* endpoints, activates data interface (if needed), maybe sets MTU.
* all pure cdc, except for certain firmware workarounds, and knowing
* don't do reset all the way. So the packet filter should
* be set to a sane initial value.
*/
- usb_control_msg(dev->udev,
- usb_sndctrlpipe(dev->udev, 0),
- USB_CDC_SET_ETHERNET_PACKET_FILTER,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- USB_CDC_PACKET_TYPE_ALL_MULTICAST | USB_CDC_PACKET_TYPE_DIRECTED | USB_CDC_PACKET_TYPE_BROADCAST,
- intf->cur_altsetting->desc.bInterfaceNumber,
- NULL,
- 0,
- USB_CTRL_SET_TIMEOUT
- );
+ usbnet_cdc_update_filter(dev);
+
return 0;
bad_desc:
return status;
}
- /* FIXME cdc-ether has some multicast code too, though it complains
- * in routine cases. info->ether describes the multicast support.
- * Implement that here, manipulating the cdc filter as needed.
- */
return 0;
}
EXPORT_SYMBOL_GPL(usbnet_cdc_bind);
.bind = usbnet_cdc_bind,
.unbind = usbnet_cdc_unbind,
.status = usbnet_cdc_status,
+ .set_rx_mode = usbnet_cdc_update_filter,
.manage_power = usbnet_manage_power,
};
.bind = usbnet_cdc_bind,
.unbind = usbnet_cdc_unbind,
.status = usbnet_cdc_status,
+ .set_rx_mode = usbnet_cdc_update_filter,
.manage_power = usbnet_manage_power,
};
case -ESHUTDOWN:
netif_device_detach(tp->netdev);
case -ENOENT:
+ case -EPROTO:
+ netif_info(tp, intr, tp->netdev,
+ "Stop submitting intr, status %d\n", status);
return;
case -EOVERFLOW:
netif_info(tp, intr, tp->netdev, "intr status -EOVERFLOW\n");
if (res)
goto out;
+ /* set speed to 0 to avoid autoresume try to submit rx */
+ tp->speed = 0;
+
res = usb_autopm_get_interface(tp->intf);
if (res < 0) {
free_all_mem(tp);
clear_bit(WORK_ENABLE, &tp->flags);
usb_kill_urb(tp->intr_urb);
cancel_delayed_work_sync(&tp->schedule);
+
+ /* disable the tx/rx, if the workqueue has enabled them. */
if (tp->speed & LINK_STATUS)
tp->rtl_ops.disable(tp);
}
* be disable when autoresume occurs, because the
* netif_running() would be false.
*/
- if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
- rtl_runtime_suspend_enable(tp, false);
- clear_bit(SELECTIVE_SUSPEND, &tp->flags);
- }
+ rtl_runtime_suspend_enable(tp, false);
tasklet_disable(&tp->tl);
tp->rtl_ops.down(tp);
netif_device_detach(netdev);
}
- if (netif_running(netdev)) {
+ if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) {
clear_bit(WORK_ENABLE, &tp->flags);
usb_kill_urb(tp->intr_urb);
tasklet_disable(&tp->tl);
set_bit(WORK_ENABLE, &tp->flags);
}
usb_submit_urb(tp->intr_urb, GFP_KERNEL);
+ } else if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
+ clear_bit(SELECTIVE_SUSPEND, &tp->flags);
}
mutex_unlock(&tp->control);
clear_bit(EVENT_LINK_CHANGE, &dev->flags);
}
+static void usbnet_set_rx_mode(struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ usbnet_defer_kevent(dev, EVENT_SET_RX_MODE);
+}
+
+static void __handle_set_rx_mode(struct usbnet *dev)
+{
+ if (dev->driver_info->set_rx_mode)
+ (dev->driver_info->set_rx_mode)(dev);
+
+ clear_bit(EVENT_SET_RX_MODE, &dev->flags);
+}
+
/* work that cannot be done in interrupt context uses keventd.
*
* NOTE: with 2.5 we could do more of this using completion callbacks,
if (test_bit (EVENT_LINK_CHANGE, &dev->flags))
__handle_link_change(dev);
+ if (test_bit (EVENT_SET_RX_MODE, &dev->flags))
+ __handle_set_rx_mode(dev);
+
+
if (dev->flags)
netdev_dbg(dev->net, "kevent done, flags = 0x%lx\n", dev->flags);
}
.ndo_stop = usbnet_stop,
.ndo_start_xmit = usbnet_start_xmit,
.ndo_tx_timeout = usbnet_tx_timeout,
+ .ndo_set_rx_mode = usbnet_set_rx_mode,
.ndo_change_mtu = usbnet_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
break;
case VIRTIO_NET_HDR_GSO_UDP:
+ {
+ static bool warned;
+
+ if (!warned) {
+ warned = true;
+ netdev_warn(dev,
+ "host using disabled UFO feature; please fix it\n");
+ }
skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
break;
+ }
case VIRTIO_NET_HDR_GSO_TCPV6:
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
break;
hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
- else if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP)
- hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_UDP;
else
BUG();
if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_ECN)
dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
- dev->hw_features |= NETIF_F_TSO | NETIF_F_UFO
+ dev->hw_features |= NETIF_F_TSO
| NETIF_F_TSO_ECN | NETIF_F_TSO6;
}
/* Individual feature bits: what can host handle? */
dev->hw_features |= NETIF_F_TSO6;
if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
dev->hw_features |= NETIF_F_TSO_ECN;
- if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UFO))
- dev->hw_features |= NETIF_F_UFO;
if (gso)
- dev->features |= dev->hw_features & (NETIF_F_ALL_TSO|NETIF_F_UFO);
+ dev->features |= dev->hw_features & NETIF_F_ALL_TSO;
/* (!csum && gso) case will be fixed by register_netdev() */
}
if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
/* If we can receive ANY GSO packets, we must allocate large ones. */
if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) ||
- virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN) ||
- virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UFO))
+ virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN))
vi->big_packets = true;
if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
static unsigned int features[] = {
VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GUEST_CSUM,
VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC,
- VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6,
+ VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_TSO6,
VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6,
- VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO,
+ VIRTIO_NET_F_GUEST_ECN,
VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ,
VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN,
VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ,
struct ath_regulatory {
char alpha2[2];
+ enum nl80211_dfs_regions region;
u16 country_code;
u16 max_power_level;
u16 current_rd;
{
struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
- if (reg->power_limit != new_txpow) {
+ if (reg->power_limit != new_txpow)
ath9k_hw_set_txpowerlimit(ah, new_txpow, false);
- /* read back in case value is clamped */
- *txpower = reg->max_power_level;
- }
+
+ /* read back in case value is clamped */
+ *txpower = reg->max_power_level;
}
EXPORT_SYMBOL(ath9k_cmn_update_txpow);
"%2d %2x %1x %2x %2x\n",
i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset,
(*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3),
- val[2] & (0x7 << (i * 3)) >> (i * 3),
+ (val[2] & (0x7 << (i * 3))) >> (i * 3),
(*dcuBase & (0x1f << dcuOffset)) >> dcuOffset);
}
#endif
};
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
+static void ath9k_set_mcc_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
+{
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ if (!ath9k_is_chanctx_enabled())
+ return;
+
+ hw->flags |= IEEE80211_HW_QUEUE_CONTROL;
+ hw->queues = ATH9K_NUM_TX_QUEUES;
+ hw->offchannel_tx_hw_queue = hw->queues - 1;
+ hw->wiphy->interface_modes &= ~ BIT(NL80211_IFTYPE_WDS);
+ hw->wiphy->iface_combinations = if_comb_multi;
+ hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_multi);
+ hw->wiphy->max_scan_ssids = 255;
+ hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
+ hw->wiphy->max_remain_on_channel_duration = 10000;
+ hw->chanctx_data_size = sizeof(void *);
+ hw->extra_beacon_tailroom =
+ sizeof(struct ieee80211_p2p_noa_attr) + 9;
+
+ ath_dbg(common, CHAN_CTX, "Use channel contexts\n");
+}
+#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
+
static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
{
struct ath_hw *ah = sc->sc_ah;
IEEE80211_HW_SPECTRUM_MGMT |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
IEEE80211_HW_SUPPORTS_RC_TABLE |
- IEEE80211_HW_QUEUE_CONTROL |
IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
if (ath9k_ps_enable)
hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
}
-#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
-
- if (ath9k_is_chanctx_enabled()) {
- hw->wiphy->interface_modes &= ~ BIT(NL80211_IFTYPE_WDS);
- hw->wiphy->iface_combinations = if_comb_multi;
- hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_multi);
- hw->wiphy->max_scan_ssids = 255;
- hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
- hw->wiphy->max_remain_on_channel_duration = 10000;
- hw->chanctx_data_size = sizeof(void *);
- hw->extra_beacon_tailroom =
- sizeof(struct ieee80211_p2p_noa_attr) + 9;
-
- ath_dbg(common, CHAN_CTX, "Use channel contexts\n");
- }
-
-#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
-
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
- /* allow 4 queues per channel context +
- * 1 cab queue + 1 offchannel tx queue
- */
- hw->queues = ATH9K_NUM_TX_QUEUES;
- /* last queue for offchannel */
- hw->offchannel_tx_hw_queue = hw->queues - 1;
+ hw->queues = 4;
hw->max_rates = 4;
hw->max_listen_interval = 10;
hw->max_rate_tries = 10;
hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
&common->sbands[IEEE80211_BAND_5GHZ];
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
+ ath9k_set_mcc_capab(sc, hw);
+#endif
ath9k_init_wow(hw);
ath9k_cmn_reload_chainmask(ah);
{
int i;
+ if (!ath9k_is_chanctx_enabled())
+ return;
+
for (i = 0; i < IEEE80211_NUM_ACS; i++)
vif->hw_queue[i] = i;
if (txq->stopped &&
txq->pending_frames < sc->tx.txq_max_pending[q]) {
- ieee80211_wake_queue(sc->hw, info->hw_queue);
+ if (ath9k_is_chanctx_enabled())
+ ieee80211_wake_queue(sc->hw, info->hw_queue);
+ else
+ ieee80211_wake_queue(sc->hw, q);
txq->stopped = false;
}
}
fi->txq = q;
if (++txq->pending_frames > sc->tx.txq_max_pending[q] &&
!txq->stopped) {
- ieee80211_stop_queue(sc->hw, info->hw_queue);
+ if (ath9k_is_chanctx_enabled())
+ ieee80211_stop_queue(sc->hw, info->hw_queue);
+ else
+ ieee80211_stop_queue(sc->hw, q);
txq->stopped = true;
}
}
if (!request)
return;
+ reg->region = request->dfs_region;
switch (request->initiator) {
case NL80211_REGDOM_SET_BY_CORE:
/*
return SD_NO_CTL;
}
+ if (ath_regd_get_eepromRD(reg) == CTRY_DEFAULT) {
+ switch (reg->region) {
+ case NL80211_DFS_FCC:
+ return CTL_FCC;
+ case NL80211_DFS_ETSI:
+ return CTL_ETSI;
+ case NL80211_DFS_JP:
+ return CTL_MKK;
+ default:
+ break;
+ }
+ }
+
switch (band) {
case IEEE80211_BAND_2GHZ:
return reg->regpair->reg_2ghz_ctl;
struct brcmf_sdio_dev *sdiodev)
{
int i;
- uint fw_len, nv_len;
char end;
for (i = 0; i < ARRAY_SIZE(brcmf_fwname_data); i++) {
return -ENODEV;
}
- fw_len = sizeof(sdiodev->fw_name) - 1;
- nv_len = sizeof(sdiodev->nvram_name) - 1;
/* check if firmware path is provided by module parameter */
if (brcmf_firmware_path[0] != '\0') {
- strncpy(sdiodev->fw_name, brcmf_firmware_path, fw_len);
- strncpy(sdiodev->nvram_name, brcmf_firmware_path, nv_len);
- fw_len -= strlen(sdiodev->fw_name);
- nv_len -= strlen(sdiodev->nvram_name);
+ strlcpy(sdiodev->fw_name, brcmf_firmware_path,
+ sizeof(sdiodev->fw_name));
+ strlcpy(sdiodev->nvram_name, brcmf_firmware_path,
+ sizeof(sdiodev->nvram_name));
end = brcmf_firmware_path[strlen(brcmf_firmware_path) - 1];
if (end != '/') {
- strncat(sdiodev->fw_name, "/", fw_len);
- strncat(sdiodev->nvram_name, "/", nv_len);
- fw_len--;
- nv_len--;
+ strlcat(sdiodev->fw_name, "/",
+ sizeof(sdiodev->fw_name));
+ strlcat(sdiodev->nvram_name, "/",
+ sizeof(sdiodev->nvram_name));
}
}
- strncat(sdiodev->fw_name, brcmf_fwname_data[i].bin, fw_len);
- strncat(sdiodev->nvram_name, brcmf_fwname_data[i].nv, nv_len);
+ strlcat(sdiodev->fw_name, brcmf_fwname_data[i].bin,
+ sizeof(sdiodev->fw_name));
+ strlcat(sdiodev->nvram_name, brcmf_fwname_data[i].nv,
+ sizeof(sdiodev->nvram_name));
return 0;
}
u32 queues, bool drop)
{
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+ u32 scd_queues;
mutex_lock(&priv->mutex);
IWL_DEBUG_MAC80211(priv, "enter\n");
goto done;
}
- /*
- * mac80211 will not push any more frames for transmit
- * until the flush is completed
- */
- if (drop) {
- IWL_DEBUG_MAC80211(priv, "send flush command\n");
- if (iwlagn_txfifo_flush(priv, 0)) {
- IWL_ERR(priv, "flush request fail\n");
- goto done;
- }
+ scd_queues = BIT(priv->cfg->base_params->num_of_queues) - 1;
+ scd_queues &= ~(BIT(IWL_IPAN_CMD_QUEUE_NUM) |
+ BIT(IWL_DEFAULT_CMD_QUEUE_NUM));
+
+ if (vif)
+ scd_queues &= ~BIT(vif->hw_queue[IEEE80211_AC_VO]);
+
+ IWL_DEBUG_TX_QUEUES(priv, "Flushing SCD queues: 0x%x\n", scd_queues);
+ if (iwlagn_txfifo_flush(priv, scd_queues)) {
+ IWL_ERR(priv, "flush request fail\n");
+ goto done;
}
- IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n");
+ IWL_DEBUG_TX_QUEUES(priv, "wait transmit/flush all frames\n");
iwl_trans_wait_tx_queue_empty(priv->trans, 0xffffffff);
done:
mutex_unlock(&priv->mutex);
#define IWL8000_TX_POWER_VERSION 0xffff /* meaningless */
#define IWL8000_FW_PRE "iwlwifi-8000"
-#define IWL8000_MODULE_FIRMWARE(api) IWL8000_FW_PRE __stringify(api) ".ucode"
+#define IWL8000_MODULE_FIRMWARE(api) \
+ IWL8000_FW_PRE "-" __stringify(api) ".ucode"
#define NVM_HW_SECTION_NUM_FAMILY_8000 10
#define DEFAULT_NVM_FILE_FAMILY_8000 "iwl_nvm_8000.bin"
* Set during transport allocation.
* @hw_id_str: a string with info about HW ID. Set during transport allocation.
* @pm_support: set to true in start_hw if link pm is supported
+ * @ltr_enabled: set to true if the LTR is enabled
* @dev_cmd_pool: pool for Tx cmd allocation - for internal use only.
* The user should use iwl_trans_{alloc,free}_tx_cmd.
* @dev_cmd_headroom: room needed for the transport's private use before the
u8 rx_mpdu_cmd, rx_mpdu_cmd_hdr_size;
bool pm_support;
+ bool ltr_enabled;
/* The following fields are internal only */
struct kmem_cache *dev_cmd_pool;
};
static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = {
- cpu_to_le32(0x28412201),
- cpu_to_le32(0x11118451),
+ cpu_to_le32(0x2e402280),
+ cpu_to_le32(0x7711a751),
};
struct corunning_block_luts {
};
static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = {
- cpu_to_le32(0x28412201),
- cpu_to_le32(0x11118451),
+ cpu_to_le32(0x2e402280),
+ cpu_to_le32(0x7711a751),
};
struct corunning_block_luts {
/* Power Management Commands, Responses, Notifications */
+/**
+ * enum iwl_ltr_config_flags - masks for LTR config command flags
+ * @LTR_CFG_FLAG_FEATURE_ENABLE: Feature operational status
+ * @LTR_CFG_FLAG_HW_DIS_ON_SHADOW_REG_ACCESS: allow LTR change on shadow
+ * memory access
+ * @LTR_CFG_FLAG_HW_EN_SHRT_WR_THROUGH: allow LTR msg send on ANY LTR
+ * reg change
+ * @LTR_CFG_FLAG_HW_DIS_ON_D0_2_D3: allow LTR msg send on transition from
+ * D0 to D3
+ * @LTR_CFG_FLAG_SW_SET_SHORT: fixed static short LTR register
+ * @LTR_CFG_FLAG_SW_SET_LONG: fixed static short LONG register
+ * @LTR_CFG_FLAG_DENIE_C10_ON_PD: allow going into C10 on PD
+ */
+enum iwl_ltr_config_flags {
+ LTR_CFG_FLAG_FEATURE_ENABLE = BIT(0),
+ LTR_CFG_FLAG_HW_DIS_ON_SHADOW_REG_ACCESS = BIT(1),
+ LTR_CFG_FLAG_HW_EN_SHRT_WR_THROUGH = BIT(2),
+ LTR_CFG_FLAG_HW_DIS_ON_D0_2_D3 = BIT(3),
+ LTR_CFG_FLAG_SW_SET_SHORT = BIT(4),
+ LTR_CFG_FLAG_SW_SET_LONG = BIT(5),
+ LTR_CFG_FLAG_DENIE_C10_ON_PD = BIT(6),
+};
+
+/**
+ * struct iwl_ltr_config_cmd - configures the LTR
+ * @flags: See %enum iwl_ltr_config_flags
+ */
+struct iwl_ltr_config_cmd {
+ __le32 flags;
+ __le32 static_long;
+ __le32 static_short;
+} __packed;
+
/* Radio LP RX Energy Threshold measured in dBm */
#define POWER_LPRX_RSSI_THRESHOLD 75
#define POWER_LPRX_RSSI_THRESHOLD_MAX 94
#define POWER_LPRX_RSSI_THRESHOLD_MIN 30
/**
- * enum iwl_scan_flags - masks for power table command flags
+ * enum iwl_power_flags - masks for power table command flags
* @POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off
* receiver and transmitter. '0' - does not allow.
* @POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK: '0' Driver disables power management,
/* Power - legacy power table command */
POWER_TABLE_CMD = 0x77,
PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78,
+ LTR_CONFIG = 0xee,
/* Thermal Throttling*/
REPLY_THERMAL_MNG_BACKOFF = 0x7e,
/* Initialize tx backoffs to the minimal possible */
iwl_mvm_tt_tx_backoff(mvm, 0);
+ if (mvm->trans->ltr_enabled) {
+ struct iwl_ltr_config_cmd cmd = {
+ .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE),
+ };
+
+ WARN_ON(iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0,
+ sizeof(cmd), &cmd));
+ }
+
ret = iwl_mvm_power_update_device(mvm);
if (ret)
goto error;
}
if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE &&
- !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status))
+ !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status) &&
+ !test_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status))
goto drop;
/* treat non-bufferable MMPDUs as broadcast if sta is sleeping */
if (changes & BSS_CHANGED_BEACON &&
iwl_mvm_mac_ctxt_beacon_changed(mvm, vif))
IWL_WARN(mvm, "Failed updating beacon data\n");
+
+ if (changes & BSS_CHANGED_TXPOWER) {
+ IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d\n",
+ bss_conf->txpower);
+ iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower);
+ }
+
}
static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
/* Set the node address */
memcpy(aux_roc_req.node_addr, vif->addr, ETH_ALEN);
+ lockdep_assert_held(&mvm->mutex);
+
+ spin_lock_bh(&mvm->time_event_lock);
+
+ if (WARN_ON(te_data->id == HOT_SPOT_CMD)) {
+ spin_unlock_bh(&mvm->time_event_lock);
+ return -EIO;
+ }
+
te_data->vif = vif;
te_data->duration = duration;
te_data->id = HOT_SPOT_CMD;
- lockdep_assert_held(&mvm->mutex);
-
- spin_lock_bh(&mvm->time_event_lock);
- list_add_tail(&te_data->list, &mvm->time_event_list);
spin_unlock_bh(&mvm->time_event_lock);
/*
IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value,
duration, type);
+ mutex_lock(&mvm->mutex);
+
switch (vif->type) {
case NL80211_IFTYPE_STATION:
/* Use aux roc framework (HS20) */
ret = iwl_mvm_send_aux_roc_cmd(mvm, channel,
vif, duration);
- return ret;
+ goto out_unlock;
case NL80211_IFTYPE_P2P_DEVICE:
/* handle below */
break;
default:
IWL_ERR(mvm, "vif isn't P2P_DEVICE: %d\n", vif->type);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out_unlock;
}
- mutex_lock(&mvm->mutex);
-
for (i = 0; i < NUM_PHY_CTX; i++) {
phy_ctxt = &mvm->phy_ctxts[i];
if (phy_ctxt->ref == 0 || mvmvif->phy_ctxt == phy_ctxt)
CMD(DTS_MEASUREMENT_NOTIFICATION),
CMD(REPLY_THERMAL_MNG_BACKOFF),
CMD(MAC_PM_POWER_TABLE),
+ CMD(LTR_CONFIG),
CMD(BT_COEX_CI),
CMD(BT_COEX_UPDATE_SW_BOOST),
CMD(BT_COEX_UPDATE_CORUN_LUT),
basic_ssid ? 1 : 0);
cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL |
- TX_CMD_FLG_BT_DIS);
+ 3 << TX_CMD_FLG_BT_PRIO_POS);
+
cmd->tx_cmd.sta_id = mvm->aux_sta.sta_id;
cmd->tx_cmd.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
cmd->tx_cmd.rate_n_flags =
te_data->running = false;
te_data->vif = NULL;
te_data->uid = 0;
+ te_data->id = TE_MAX;
} else if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_START) {
- set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
set_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status);
te_data->running = true;
ieee80211_ready_on_channel(mvm->hw); /* Start TE */
/*
* for data packets, rate info comes from the table inside the fw. This
- * table is controlled by LINK_QUALITY commands. Exclude ctrl port
- * frames like EAPOLs which should be treated as mgmt frames. This
- * avoids them being sent initially in high rates which increases the
- * chances for completion of the 4-Way handshake.
+ * table is controlled by LINK_QUALITY commands
*/
- if (ieee80211_is_data(fc) && sta &&
- !(info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) {
+ if (ieee80211_is_data(fc) && sta) {
tx_cmd->initial_rate_index = 0;
tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE);
return;
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
u16 lctl;
+ u16 cap;
/*
* HW bug W/A for instability in PCIe bus L0S->L1 transition.
* power savings, even without L1.
*/
pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_LNKCTL, &lctl);
- if (lctl & PCI_EXP_LNKCTL_ASPM_L1) {
- /* L1-ASPM enabled; disable(!) L0S */
+ if (lctl & PCI_EXP_LNKCTL_ASPM_L1)
iwl_set_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
- dev_info(trans->dev, "L1 Enabled; Disabling L0S\n");
- } else {
- /* L1-ASPM disabled; enable(!) L0S */
+ else
iwl_clear_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
- dev_info(trans->dev, "L1 Disabled; Enabling L0S\n");
- }
trans->pm_support = !(lctl & PCI_EXP_LNKCTL_ASPM_L0S);
+
+ pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_DEVCTL2, &cap);
+ trans->ltr_enabled = cap & PCI_EXP_DEVCTL2_LTR_EN;
+ dev_info(trans->dev, "L1 %sabled - LTR %sabled\n",
+ (lctl & PCI_EXP_LNKCTL_ASPM_L1) ? "En" : "Dis",
+ trans->ltr_enabled ? "En" : "Dis");
}
/*
ret = iwl_poll_bit(trans, CSR_RESET,
CSR_RESET_REG_FLAG_MASTER_DISABLED,
CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
- if (ret)
+ if (ret < 0)
IWL_WARN(trans, "Master Disable Timed Out, 100 usec\n");
IWL_DEBUG_INFO(trans, "stop master\n");
msleep(25);
}
- IWL_DEBUG_INFO(trans, "got NIC after %d iterations\n", iter);
+ IWL_ERR(trans, "Couldn't prepare the card\n");
return ret;
}
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
25000);
- if (ret) {
+ if (ret < 0) {
IWL_ERR(trans, "Failed to resume the device (mac ready)\n");
return ret;
}
mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, start_win);
del_timer_sync(&tbl->timer_context.timer);
+ tbl->timer_context.timer_is_set = false;
spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
list_del(&tbl->list);
(struct reorder_tmr_cnxt *) context;
int start_win, seq_num;
+ ctx->timer_is_set = false;
seq_num = mwifiex_11n_find_last_seq_num(ctx);
if (seq_num < 0)
new_node->timer_context.ptr = new_node;
new_node->timer_context.priv = priv;
+ new_node->timer_context.timer_is_set = false;
init_timer(&new_node->timer_context.timer);
new_node->timer_context.timer.function = mwifiex_flush_data;
spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
}
+static void
+mwifiex_11n_rxreorder_timer_restart(struct mwifiex_rx_reorder_tbl *tbl)
+{
+ u32 min_flush_time;
+
+ if (tbl->win_size >= MWIFIEX_BA_WIN_SIZE_32)
+ min_flush_time = MIN_FLUSH_TIMER_15_MS;
+ else
+ min_flush_time = MIN_FLUSH_TIMER_MS;
+
+ mod_timer(&tbl->timer_context.timer,
+ jiffies + msecs_to_jiffies(min_flush_time * tbl->win_size));
+
+ tbl->timer_context.timer_is_set = true;
+}
+
/*
* This function prepares command for adding a BA request.
*
u8 *ta, u8 pkt_type, void *payload)
{
struct mwifiex_rx_reorder_tbl *tbl;
- int start_win, end_win, win_size;
+ int prev_start_win, start_win, end_win, win_size;
u16 pkt_index;
bool init_window_shift = false;
+ int ret = 0;
tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
if (!tbl) {
if (pkt_type != PKT_TYPE_BAR)
mwifiex_11n_dispatch_pkt(priv, payload);
- return 0;
+ return ret;
}
if ((pkt_type == PKT_TYPE_AMSDU) && !tbl->amsdu) {
mwifiex_11n_dispatch_pkt(priv, payload);
- return 0;
+ return ret;
}
start_win = tbl->start_win;
+ prev_start_win = start_win;
win_size = tbl->win_size;
end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
if (tbl->flags & RXREOR_INIT_WINDOW_SHIFT) {
init_window_shift = true;
tbl->flags &= ~RXREOR_INIT_WINDOW_SHIFT;
}
- mod_timer(&tbl->timer_context.timer,
- jiffies + msecs_to_jiffies(MIN_FLUSH_TIMER_MS * win_size));
if (tbl->flags & RXREOR_FORCE_NO_DROP) {
dev_dbg(priv->adapter->dev,
if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {
if (seq_num >= ((start_win + TWOPOW11) &
(MAX_TID_VALUE - 1)) &&
- seq_num < start_win)
- return -1;
+ seq_num < start_win) {
+ ret = -1;
+ goto done;
+ }
} else if ((seq_num < start_win) ||
- (seq_num > (start_win + TWOPOW11))) {
- return -1;
+ (seq_num >= (start_win + TWOPOW11))) {
+ ret = -1;
+ goto done;
}
}
else
pkt_index = (seq_num+MAX_TID_VALUE) - start_win;
- if (tbl->rx_reorder_ptr[pkt_index])
- return -1;
+ if (tbl->rx_reorder_ptr[pkt_index]) {
+ ret = -1;
+ goto done;
+ }
tbl->rx_reorder_ptr[pkt_index] = payload;
}
*/
mwifiex_11n_scan_and_dispatch(priv, tbl);
- return 0;
+done:
+ if (!tbl->timer_context.timer_is_set ||
+ prev_start_win != tbl->start_win)
+ mwifiex_11n_rxreorder_timer_restart(tbl);
+ return ret;
}
/*
#define _MWIFIEX_11N_RXREORDER_H_
#define MIN_FLUSH_TIMER_MS 50
+#define MIN_FLUSH_TIMER_15_MS 15
+#define MWIFIEX_BA_WIN_SIZE_32 32
#define PKT_TYPE_BAR 0xE7
#define MAX_TID_VALUE (2 << 11)
struct timer_list timer;
struct mwifiex_rx_reorder_tbl *ptr;
struct mwifiex_private *priv;
+ u8 timer_is_set;
};
struct mwifiex_rx_reorder_tbl {
/* Ovislink */
{ USB_DEVICE(0x1b75, 0x3071) },
{ USB_DEVICE(0x1b75, 0x3072) },
+ { USB_DEVICE(0x1b75, 0xa200) },
/* Para */
{ USB_DEVICE(0x20b8, 0x8888) },
/* Pegatron */
rtl_easy_concurrent_retrytimer_callback, (unsigned long)hw);
/* <2> work queue */
rtlpriv->works.hw = hw;
- rtlpriv->works.rtl_wq = alloc_workqueue(rtlpriv->cfg->name, 0, 0);
+ rtlpriv->works.rtl_wq = alloc_workqueue("%s", 0, 0, rtlpriv->cfg->name);
INIT_DELAYED_WORK(&rtlpriv->works.watchdog_wq,
(void *)rtl_watchdog_wq_callback);
INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq,
.flush = rtl_op_flush,
};
EXPORT_SYMBOL_GPL(rtl_ops);
+
+bool rtl_btc_status_false(void)
+{
+ return false;
+}
+EXPORT_SYMBOL_GPL(rtl_btc_status_false);
u32 mask, u32 data);
void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data);
bool rtl_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb);
+bool rtl_btc_status_false(void);
#endif
rtl_pci_reset_trx_ring(hw);
rtlpci->driver_is_goingto_unload = false;
- if (rtlpriv->cfg->ops->get_btc_status()) {
+ if (rtlpriv->cfg->ops->get_btc_status &&
+ rtlpriv->cfg->ops->get_btc_status()) {
rtlpriv->btcoexist.btc_ops->btc_init_variables(rtlpriv);
rtlpriv->btcoexist.btc_ops->btc_init_hal_vars(rtlpriv);
}
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
-void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
+void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw,
+ bool (*cmd_send_packet)(struct ieee80211_hw *, struct sk_buff *))
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
memcpy((u8 *)skb_put(skb, totalpacketlen),
&reserved_page_packet, totalpacketlen);
- rtstatus = rtl_cmd_send_packet(hw, skb);
+ if (cmd_send_packet)
+ rtstatus = cmd_send_packet(hw, skb);
+ else
+ rtstatus = rtl_cmd_send_packet(hw, skb);
if (rtstatus)
b_dlok = true;
u32 cmd_len, u8 *p_cmdbuffer);
void rtl92c_firmware_selfreset(struct ieee80211_hw *hw);
void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
-void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished);
+void rtl92c_set_fw_rsvdpagepkt
+ (struct ieee80211_hw *hw,
+ bool (*cmd_send_packet)(struct ieee80211_hw *, struct sk_buff *));
void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus);
void usb_writeN_async(struct rtl_priv *rtlpriv, u32 addr, void *data, u16 len);
void rtl92c_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state);
LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 16, 4)
#define GET_C2H_CMD_FEEDBACK_CCX_SEQ(__pcmdfbhdr) \
LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 20, 12)
+#define GET_RX_STATUS_DESC_BUFF_ADDR(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 24, 0, 32)
#define CHIP_VER_B BIT(4)
#define CHIP_BONDING_IDENTIFIER(_value) (((_value) >> 22) & 0x3)
rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2,
tmp_reg422 & (~BIT(6)));
- rtl92c_set_fw_rsvdpagepkt(hw, 0);
+ rtl92c_set_fw_rsvdpagepkt(hw, NULL);
_rtl92ce_set_bcn_ctrl_reg(hw, BIT(3), 0);
_rtl92ce_set_bcn_ctrl_reg(hw, 0, BIT(4));
.phy_lc_calibrate = _rtl92ce_phy_lc_calibrate,
.phy_set_bw_mode_callback = rtl92ce_phy_set_bw_mode_callback,
.dm_dynamic_txpower = rtl92ce_dm_dynamic_txpower,
+ .get_btc_status = rtl_btc_status_false,
};
static struct rtl_mod_params rtl92ce_mod_params = {
case HW_DESC_RXPKT_LEN:
ret = GET_RX_DESC_PKT_LEN(pdesc);
break;
+ case HW_DESC_RXBUFF_ADDR:
+ ret = GET_RX_STATUS_DESC_BUFF_ADDR(pdesc);
+ break;
default:
RT_ASSERT(false, "ERR rxdesc :%d not process\n",
desc_name);
}
}
+bool usb_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+ /* Currently nothing happens here.
+ * Traffic stops after some seconds in WPA2 802.11n mode.
+ * Maybe because rtl8192cu chip should be set from here?
+ * If I understand correctly, the realtek vendor driver sends some urbs
+ * if its "here".
+ *
+ * This is maybe necessary:
+ * rtlpriv->cfg->ops->fill_tx_cmddesc(hw, buffer, 1, 1, skb);
+ */
+ return true;
+}
+
void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
recover = true;
rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2,
tmp_reg422 & (~BIT(6)));
- rtl92c_set_fw_rsvdpagepkt(hw, 0);
+ rtl92c_set_fw_rsvdpagepkt(hw,
+ &usb_cmd_send_packet);
_rtl92cu_set_bcn_ctrl_reg(hw, BIT(3), 0);
_rtl92cu_set_bcn_ctrl_reg(hw, 0, BIT(4));
if (recover)
void rtl92cu_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid);
int rtl92c_download_fw(struct ieee80211_hw *hw);
void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
-void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished);
void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus);
void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
u8 element_id, u32 cmd_len, u8 *p_cmdbuffer);
}
}
+/* get bt coexist status */
+static bool rtl92cu_get_btc_status(void)
+{
+ return false;
+}
+
static struct rtl_hal_ops rtl8192cu_hal_ops = {
.init_sw_vars = rtl92cu_init_sw_vars,
.deinit_sw_vars = rtl92cu_deinit_sw_vars,
.phy_set_bw_mode_callback = rtl92cu_phy_set_bw_mode_callback,
.dm_dynamic_txpower = rtl92cu_dm_dynamic_txpower,
.fill_h2c_cmd = rtl92c_fill_h2c_cmd,
+ .get_btc_status = rtl92cu_get_btc_status,
};
static struct rtl_mod_params rtl92cu_mod_params = {
.get_rfreg = rtl92d_phy_query_rf_reg,
.set_rfreg = rtl92d_phy_set_rf_reg,
.linked_set_reg = rtl92d_linked_set_reg,
+ .get_btc_status = rtl_btc_status_false,
};
static struct rtl_mod_params rtl92de_mod_params = {
}
break;
default:
- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG,
"switch case not process %x\n", variable);
break;
}
acm_ctrl &= (~ACMHW_BEQEN);
break;
default:
- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG,
"switch case not process\n");
break;
}
}
break;
default:
- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG,
"switch case not process %x\n", variable);
break;
}
enc_algo = CAM_AES;
break;
default:
- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG,
"switch case not process\n");
enc_algo = CAM_TKIP;
break;
/* DWORD 6 */
#define SET_RX_STATUS__DESC_BUFF_ADDR(__pdesc, __val) \
SET_BITS_OFFSET_LE(__pdesc + 24, 0, 32, __val)
+#define GET_RX_STATUS_DESC_BUFF_ADDR(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 24, 0, 32)
#define SE_RX_HAL_IS_CCK_RATE(_pdesc)\
(GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE1M || \
static void rtl92se_fw_cb(const struct firmware *firmware, void *context)
{
struct ieee80211_hw *hw = context;
- struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
struct rt_firmware *pfirmware = NULL;
- int err;
RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
"Firmware callback routine entered!\n");
memcpy(pfirmware->sz_fw_tmpbuffer, firmware->data, firmware->size);
pfirmware->sz_fw_tmpbufferlen = firmware->size;
release_firmware(firmware);
-
- err = ieee80211_register_hw(hw);
- if (err) {
- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
- "Can't register mac80211 hw\n");
- return;
- } else {
- rtlpriv->mac80211.mac80211_registered = 1;
- }
- rtlpci->irq_alloc = 1;
- set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
-
- /*init rfkill */
- rtl_init_rfkill(hw);
}
static int rtl92s_init_sw_vars(struct ieee80211_hw *hw)
if (!rtlpriv->rtlhal.pfirmware)
return 1;
- rtlpriv->max_fw_size = RTL8190_MAX_RAW_FIRMWARE_CODE_SIZE;
-
+ rtlpriv->max_fw_size = RTL8190_MAX_FIRMWARE_CODE_SIZE*2 +
+ sizeof(struct fw_hdr);
pr_info("Driver for Realtek RTL8192SE/RTL8191SE\n"
"Loading firmware %s\n", rtlpriv->cfg->fw_name);
/* request fw */
.set_bbreg = rtl92s_phy_set_bb_reg,
.get_rfreg = rtl92s_phy_query_rf_reg,
.set_rfreg = rtl92s_phy_set_rf_reg,
+ .get_btc_status = rtl_btc_status_false,
};
static struct rtl_mod_params rtl92se_mod_params = {
case HW_DESC_RXPKT_LEN:
ret = GET_RX_STATUS_DESC_PKT_LEN(desc);
break;
+ case HW_DESC_RXBUFF_ADDR:
+ ret = GET_RX_STATUS_DESC_BUFF_ADDR(desc);
+ break;
default:
RT_ASSERT(false, "ERR rxdesc :%d not process\n",
desc_name);
struct rtl_phy *rtlphy = &rtlpriv->phy;
u8 rate_section = _rtl8821ae_get_rate_section_index(regaddr);
- if (band != BAND_ON_2_4G && band != BAND_ON_5G)
+ if (band != BAND_ON_2_4G && band != BAND_ON_5G) {
RT_TRACE(rtlpriv, COMP_INIT, DBG_WARNING, "Invalid Band %d\n", band);
-
- if (rfpath >= MAX_RF_PATH)
+ band = BAND_ON_2_4G;
+ }
+ if (rfpath >= MAX_RF_PATH) {
RT_TRACE(rtlpriv, COMP_INIT, DBG_WARNING, "Invalid RfPath %d\n", rfpath);
-
- if (txnum >= MAX_RF_PATH)
+ rfpath = MAX_RF_PATH - 1;
+ }
+ if (txnum >= MAX_RF_PATH) {
RT_TRACE(rtlpriv, COMP_INIT, DBG_WARNING, "Invalid TxNum %d\n", txnum);
-
+ txnum = MAX_RF_PATH - 1;
+ }
rtlphy->tx_power_by_rate_offset[band][rfpath][txnum][rate_section] = data;
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
"TxPwrByRateOffset[Band %d][RfPath %d][TxNum %d][RateSection %d] = 0x%x\n",
}
rtlpriv->cfg->ops->init_sw_leds(hw);
+ err = ieee80211_register_hw(hw);
+ if (err) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Can't register mac80211 hw.\n");
+ err = -ENODEV;
+ goto error_out;
+ }
+ rtlpriv->mac80211.mac80211_registered = 1;
+
+ set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
return 0;
+
error_out:
rtl_deinit_core(hw);
_rtl_usb_io_handler_release(hw);
char rx_irq_name[IRQ_NAME_SIZE]; /* DEVNAME-qN-rx */
struct xen_netif_rx_back_ring rx;
struct sk_buff_head rx_queue;
- RING_IDX rx_last_skb_slots;
- unsigned long status;
- struct timer_list rx_stalled;
+ unsigned int rx_queue_max;
+ unsigned int rx_queue_len;
+ unsigned long last_rx_time;
+ bool stalled;
struct gnttab_copy grant_copy_op[MAX_GRANT_COPY_OPS];
struct xenvif_stats stats;
};
+/* Maximum number of Rx slots a to-guest packet may use, including the
+ * slot needed for GSO meta-data.
+ */
+#define XEN_NETBK_RX_SLOTS_MAX (MAX_SKB_FRAGS + 1)
+
enum state_bit_shift {
/* This bit marks that the vif is connected */
VIF_STATUS_CONNECTED,
- /* This bit signals the RX thread that queuing was stopped (in
- * start_xmit), and either the timer fired or an RX interrupt came
- */
- QUEUE_STATUS_RX_PURGE_EVENT,
- /* This bit tells the interrupt handler that this queue was the reason
- * for the carrier off, so it should kick the thread. Only queues which
- * brought it down can turn on the carrier.
- */
- QUEUE_STATUS_RX_STALLED
};
struct xenvif {
u8 ip_csum:1;
u8 ipv6_csum:1;
- /* Internal feature information. */
- u8 can_queue:1; /* can queue packets for receiver? */
-
/* Is this interface disabled? True when backend discovers
* frontend is rogue.
*/
/* Queues */
struct xenvif_queue *queues;
unsigned int num_queues; /* active queues, resource allocated */
+ unsigned int stalled_queues;
+
+ spinlock_t lock;
#ifdef CONFIG_DEBUG_FS
struct dentry *xenvif_dbg_root;
struct net_device *dev;
};
+struct xenvif_rx_cb {
+ unsigned long expires;
+ int meta_slots_used;
+ bool full_coalesce;
+};
+
+#define XENVIF_RX_CB(skb) ((struct xenvif_rx_cb *)(skb)->cb)
+
static inline struct xenbus_device *xenvif_to_xenbus_device(struct xenvif *vif)
{
return to_xenbus_device(vif->dev->dev.parent);
int xenvif_schedulable(struct xenvif *vif);
-int xenvif_must_stop_queue(struct xenvif_queue *queue);
-
int xenvif_queue_stopped(struct xenvif_queue *queue);
void xenvif_wake_queue(struct xenvif_queue *queue);
int xenvif_dealloc_kthread(void *data);
+void xenvif_rx_queue_tail(struct xenvif_queue *queue, struct sk_buff *skb);
+
/* Determine whether the needed number of slots (req) are available,
* and set req_event if not.
*/
#define XENVIF_QUEUE_LENGTH 32
#define XENVIF_NAPI_WEIGHT 64
+/* Number of bytes allowed on the internal guest Rx queue. */
+#define XENVIF_RX_QUEUE_BYTES (XEN_NETIF_RX_RING_SIZE/2 * PAGE_SIZE)
+
/* This function is used to set SKBTX_DEV_ZEROCOPY as well as
* increasing the inflight counter. We need to increase the inflight
* counter because core driver calls into xenvif_zerocopy_callback
atomic_dec(&queue->inflight_packets);
}
-static inline void xenvif_stop_queue(struct xenvif_queue *queue)
-{
- struct net_device *dev = queue->vif->dev;
-
- if (!queue->vif->can_queue)
- return;
-
- netif_tx_stop_queue(netdev_get_tx_queue(dev, queue->id));
-}
-
int xenvif_schedulable(struct xenvif *vif)
{
return netif_running(vif->dev) &&
- test_bit(VIF_STATUS_CONNECTED, &vif->status);
+ test_bit(VIF_STATUS_CONNECTED, &vif->status) &&
+ !vif->disabled;
}
static irqreturn_t xenvif_tx_interrupt(int irq, void *dev_id)
static irqreturn_t xenvif_rx_interrupt(int irq, void *dev_id)
{
struct xenvif_queue *queue = dev_id;
- struct netdev_queue *net_queue =
- netdev_get_tx_queue(queue->vif->dev, queue->id);
- /* QUEUE_STATUS_RX_PURGE_EVENT is only set if either QDisc was off OR
- * the carrier went down and this queue was previously blocked
- */
- if (unlikely(netif_tx_queue_stopped(net_queue) ||
- (!netif_carrier_ok(queue->vif->dev) &&
- test_bit(QUEUE_STATUS_RX_STALLED, &queue->status))))
- set_bit(QUEUE_STATUS_RX_PURGE_EVENT, &queue->status);
xenvif_kick_thread(queue);
return IRQ_HANDLED;
netif_tx_wake_queue(netdev_get_tx_queue(dev, id));
}
-/* Callback to wake the queue's thread and turn the carrier off on timeout */
-static void xenvif_rx_stalled(unsigned long data)
-{
- struct xenvif_queue *queue = (struct xenvif_queue *)data;
-
- if (xenvif_queue_stopped(queue)) {
- set_bit(QUEUE_STATUS_RX_PURGE_EVENT, &queue->status);
- xenvif_kick_thread(queue);
- }
-}
-
static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct xenvif *vif = netdev_priv(dev);
struct xenvif_queue *queue = NULL;
unsigned int num_queues = vif->num_queues;
u16 index;
- int min_slots_needed;
+ struct xenvif_rx_cb *cb;
BUG_ON(skb->dev != dev);
!xenvif_schedulable(vif))
goto drop;
- /* At best we'll need one slot for the header and one for each
- * frag.
- */
- min_slots_needed = 1 + skb_shinfo(skb)->nr_frags;
-
- /* If the skb is GSO then we'll also need an extra slot for the
- * metadata.
- */
- if (skb_is_gso(skb))
- min_slots_needed++;
+ cb = XENVIF_RX_CB(skb);
+ cb->expires = jiffies + rx_drain_timeout_jiffies;
- /* If the skb can't possibly fit in the remaining slots
- * then turn off the queue to give the ring a chance to
- * drain.
- */
- if (!xenvif_rx_ring_slots_available(queue, min_slots_needed)) {
- queue->rx_stalled.function = xenvif_rx_stalled;
- queue->rx_stalled.data = (unsigned long)queue;
- xenvif_stop_queue(queue);
- mod_timer(&queue->rx_stalled,
- jiffies + rx_drain_timeout_jiffies);
- }
-
- skb_queue_tail(&queue->rx_queue, skb);
+ xenvif_rx_queue_tail(queue, skb);
xenvif_kick_thread(queue);
return NETDEV_TX_OK;
vif->queues = NULL;
vif->num_queues = 0;
+ spin_lock_init(&vif->lock);
+
dev->netdev_ops = &xenvif_netdev_ops;
dev->hw_features = NETIF_F_SG |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
init_timer(&queue->credit_timeout);
queue->credit_window_start = get_jiffies_64();
+ queue->rx_queue_max = XENVIF_RX_QUEUE_BYTES;
+
skb_queue_head_init(&queue->rx_queue);
skb_queue_head_init(&queue->tx_queue);
queue->grant_tx_handle[i] = NETBACK_INVALID_HANDLE;
}
- init_timer(&queue->rx_stalled);
-
return 0;
}
dev_set_mtu(vif->dev, ETH_DATA_LEN);
netdev_update_features(vif->dev);
set_bit(VIF_STATUS_CONNECTED, &vif->status);
- netif_carrier_on(vif->dev);
if (netif_running(vif->dev))
xenvif_up(vif);
rtnl_unlock();
disable_irq(queue->rx_irq);
}
+ queue->stalled = true;
+
task = kthread_create(xenvif_kthread_guest_rx,
(void *)queue, "%s-guest-rx", queue->name);
if (IS_ERR(task)) {
netif_napi_del(&queue->napi);
if (queue->task) {
- del_timer_sync(&queue->rx_stalled);
kthread_stop(queue->task);
queue->task = NULL;
}
bool separate_tx_rx_irq = 1;
module_param(separate_tx_rx_irq, bool, 0644);
-/* When guest ring is filled up, qdisc queues the packets for us, but we have
- * to timeout them, otherwise other guests' packets can get stuck there
+/* The time that packets can stay on the guest Rx internal queue
+ * before they are dropped.
*/
unsigned int rx_drain_timeout_msecs = 10000;
module_param(rx_drain_timeout_msecs, uint, 0444);
unsigned int rx_drain_timeout_jiffies;
+/* The length of time before the frontend is considered unresponsive
+ * because it isn't providing Rx slots.
+ */
+static unsigned int rx_stall_timeout_msecs = 60000;
+module_param(rx_stall_timeout_msecs, uint, 0444);
+static unsigned int rx_stall_timeout_jiffies;
+
unsigned int xenvif_max_queues;
module_param_named(max_queues, xenvif_max_queues, uint, 0644);
MODULE_PARM_DESC(max_queues,
s8 st);
static inline int tx_work_todo(struct xenvif_queue *queue);
-static inline int rx_work_todo(struct xenvif_queue *queue);
static struct xen_netif_rx_response *make_rx_response(struct xenvif_queue *queue,
u16 id,
return false;
}
+void xenvif_rx_queue_tail(struct xenvif_queue *queue, struct sk_buff *skb)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&queue->rx_queue.lock, flags);
+
+ __skb_queue_tail(&queue->rx_queue, skb);
+
+ queue->rx_queue_len += skb->len;
+ if (queue->rx_queue_len > queue->rx_queue_max)
+ netif_tx_stop_queue(netdev_get_tx_queue(queue->vif->dev, queue->id));
+
+ spin_unlock_irqrestore(&queue->rx_queue.lock, flags);
+}
+
+static struct sk_buff *xenvif_rx_dequeue(struct xenvif_queue *queue)
+{
+ struct sk_buff *skb;
+
+ spin_lock_irq(&queue->rx_queue.lock);
+
+ skb = __skb_dequeue(&queue->rx_queue);
+ if (skb)
+ queue->rx_queue_len -= skb->len;
+
+ spin_unlock_irq(&queue->rx_queue.lock);
+
+ return skb;
+}
+
+static void xenvif_rx_queue_maybe_wake(struct xenvif_queue *queue)
+{
+ spin_lock_irq(&queue->rx_queue.lock);
+
+ if (queue->rx_queue_len < queue->rx_queue_max)
+ netif_tx_wake_queue(netdev_get_tx_queue(queue->vif->dev, queue->id));
+
+ spin_unlock_irq(&queue->rx_queue.lock);
+}
+
+
+static void xenvif_rx_queue_purge(struct xenvif_queue *queue)
+{
+ struct sk_buff *skb;
+ while ((skb = xenvif_rx_dequeue(queue)) != NULL)
+ kfree_skb(skb);
+}
+
+static void xenvif_rx_queue_drop_expired(struct xenvif_queue *queue)
+{
+ struct sk_buff *skb;
+
+ for(;;) {
+ skb = skb_peek(&queue->rx_queue);
+ if (!skb)
+ break;
+ if (time_before(jiffies, XENVIF_RX_CB(skb)->expires))
+ break;
+ xenvif_rx_dequeue(queue);
+ kfree_skb(skb);
+ }
+}
+
/*
* Returns true if we should start a new receive buffer instead of
* adding 'size' bytes to a buffer which currently contains 'offset'
return meta;
}
-struct xenvif_rx_cb {
- int meta_slots_used;
- bool full_coalesce;
-};
-
-#define XENVIF_RX_CB(skb) ((struct xenvif_rx_cb *)(skb)->cb)
-
/*
* Set up the grant operations for this fragment. If it's a flipping
* interface, we also set up the unmap request from here.
skb_queue_head_init(&rxq);
- while ((skb = skb_dequeue(&queue->rx_queue)) != NULL) {
+ while (xenvif_rx_ring_slots_available(queue, XEN_NETBK_RX_SLOTS_MAX)
+ && (skb = xenvif_rx_dequeue(queue)) != NULL) {
RING_IDX max_slots_needed;
RING_IDX old_req_cons;
RING_IDX ring_slots_used;
int i;
+ queue->last_rx_time = jiffies;
+
/* We need a cheap worse case estimate for the number of
* slots we'll use.
*/
skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6))
max_slots_needed++;
- /* If the skb may not fit then bail out now */
- if (!xenvif_rx_ring_slots_available(queue, max_slots_needed)) {
- skb_queue_head(&queue->rx_queue, skb);
- need_to_notify = true;
- queue->rx_last_skb_slots = max_slots_needed;
- break;
- } else
- queue->rx_last_skb_slots = 0;
-
old_req_cons = queue->rx.req_cons;
XENVIF_RX_CB(skb)->meta_slots_used = xenvif_gop_skb(skb, &npo, queue);
ring_slots_used = queue->rx.req_cons - old_req_cons;
}
}
-static inline int rx_work_todo(struct xenvif_queue *queue)
-{
- return (!skb_queue_empty(&queue->rx_queue) &&
- xenvif_rx_ring_slots_available(queue, queue->rx_last_skb_slots));
-}
-
static inline int tx_work_todo(struct xenvif_queue *queue)
{
if (likely(RING_HAS_UNCONSUMED_REQUESTS(&queue->tx)))
return err;
}
-static void xenvif_start_queue(struct xenvif_queue *queue)
+static void xenvif_queue_carrier_off(struct xenvif_queue *queue)
{
- if (xenvif_schedulable(queue->vif))
- xenvif_wake_queue(queue);
+ struct xenvif *vif = queue->vif;
+
+ queue->stalled = true;
+
+ /* At least one queue has stalled? Disable the carrier. */
+ spin_lock(&vif->lock);
+ if (vif->stalled_queues++ == 0) {
+ netdev_info(vif->dev, "Guest Rx stalled");
+ netif_carrier_off(vif->dev);
+ }
+ spin_unlock(&vif->lock);
}
-/* Only called from the queue's thread, it handles the situation when the guest
- * doesn't post enough requests on the receiving ring.
- * First xenvif_start_xmit disables QDisc and start a timer, and then either the
- * timer fires, or the guest send an interrupt after posting new request. If it
- * is the timer, the carrier is turned off here.
- * */
-static void xenvif_rx_purge_event(struct xenvif_queue *queue)
+static void xenvif_queue_carrier_on(struct xenvif_queue *queue)
{
- /* Either the last unsuccesful skb or at least 1 slot should fit */
- int needed = queue->rx_last_skb_slots ?
- queue->rx_last_skb_slots : 1;
+ struct xenvif *vif = queue->vif;
- /* It is assumed that if the guest post new slots after this, the RX
- * interrupt will set the QUEUE_STATUS_RX_PURGE_EVENT bit and wake up
- * the thread again
- */
- set_bit(QUEUE_STATUS_RX_STALLED, &queue->status);
- if (!xenvif_rx_ring_slots_available(queue, needed)) {
- rtnl_lock();
- if (netif_carrier_ok(queue->vif->dev)) {
- /* Timer fired and there are still no slots. Turn off
- * everything except the interrupts
- */
- netif_carrier_off(queue->vif->dev);
- skb_queue_purge(&queue->rx_queue);
- queue->rx_last_skb_slots = 0;
- if (net_ratelimit())
- netdev_err(queue->vif->dev, "Carrier off due to lack of guest response on queue %d\n", queue->id);
- } else {
- /* Probably an another queue already turned the carrier
- * off, make sure nothing is stucked in the internal
- * queue of this queue
- */
- skb_queue_purge(&queue->rx_queue);
- queue->rx_last_skb_slots = 0;
- }
- rtnl_unlock();
- } else if (!netif_carrier_ok(queue->vif->dev)) {
- unsigned int num_queues = queue->vif->num_queues;
- unsigned int i;
- /* The carrier was down, but an interrupt kicked
- * the thread again after new requests were
- * posted
- */
- clear_bit(QUEUE_STATUS_RX_STALLED,
- &queue->status);
- rtnl_lock();
- netif_carrier_on(queue->vif->dev);
- netif_tx_wake_all_queues(queue->vif->dev);
- rtnl_unlock();
+ queue->last_rx_time = jiffies; /* Reset Rx stall detection. */
+ queue->stalled = false;
- for (i = 0; i < num_queues; i++) {
- struct xenvif_queue *temp = &queue->vif->queues[i];
+ /* All queues are ready? Enable the carrier. */
+ spin_lock(&vif->lock);
+ if (--vif->stalled_queues == 0) {
+ netdev_info(vif->dev, "Guest Rx ready");
+ netif_carrier_on(vif->dev);
+ }
+ spin_unlock(&vif->lock);
+}
- xenvif_napi_schedule_or_enable_events(temp);
- }
- if (net_ratelimit())
- netdev_err(queue->vif->dev, "Carrier on again\n");
- } else {
- /* Queuing were stopped, but the guest posted
- * new requests and sent an interrupt
- */
- clear_bit(QUEUE_STATUS_RX_STALLED,
- &queue->status);
- del_timer_sync(&queue->rx_stalled);
- xenvif_start_queue(queue);
+static bool xenvif_rx_queue_stalled(struct xenvif_queue *queue)
+{
+ RING_IDX prod, cons;
+
+ prod = queue->rx.sring->req_prod;
+ cons = queue->rx.req_cons;
+
+ return !queue->stalled
+ && prod - cons < XEN_NETBK_RX_SLOTS_MAX
+ && time_after(jiffies,
+ queue->last_rx_time + rx_stall_timeout_jiffies);
+}
+
+static bool xenvif_rx_queue_ready(struct xenvif_queue *queue)
+{
+ RING_IDX prod, cons;
+
+ prod = queue->rx.sring->req_prod;
+ cons = queue->rx.req_cons;
+
+ return queue->stalled
+ && prod - cons >= XEN_NETBK_RX_SLOTS_MAX;
+}
+
+static bool xenvif_have_rx_work(struct xenvif_queue *queue)
+{
+ return (!skb_queue_empty(&queue->rx_queue)
+ && xenvif_rx_ring_slots_available(queue, XEN_NETBK_RX_SLOTS_MAX))
+ || xenvif_rx_queue_stalled(queue)
+ || xenvif_rx_queue_ready(queue)
+ || kthread_should_stop()
+ || queue->vif->disabled;
+}
+
+static long xenvif_rx_queue_timeout(struct xenvif_queue *queue)
+{
+ struct sk_buff *skb;
+ long timeout;
+
+ skb = skb_peek(&queue->rx_queue);
+ if (!skb)
+ return MAX_SCHEDULE_TIMEOUT;
+
+ timeout = XENVIF_RX_CB(skb)->expires - jiffies;
+ return timeout < 0 ? 0 : timeout;
+}
+
+/* Wait until the guest Rx thread has work.
+ *
+ * The timeout needs to be adjusted based on the current head of the
+ * queue (and not just the head at the beginning). In particular, if
+ * the queue is initially empty an infinite timeout is used and this
+ * needs to be reduced when a skb is queued.
+ *
+ * This cannot be done with wait_event_timeout() because it only
+ * calculates the timeout once.
+ */
+static void xenvif_wait_for_rx_work(struct xenvif_queue *queue)
+{
+ DEFINE_WAIT(wait);
+
+ if (xenvif_have_rx_work(queue))
+ return;
+
+ for (;;) {
+ long ret;
+
+ prepare_to_wait(&queue->wq, &wait, TASK_INTERRUPTIBLE);
+ if (xenvif_have_rx_work(queue))
+ break;
+ ret = schedule_timeout(xenvif_rx_queue_timeout(queue));
+ if (!ret)
+ break;
}
+ finish_wait(&queue->wq, &wait);
}
int xenvif_kthread_guest_rx(void *data)
{
struct xenvif_queue *queue = data;
- struct sk_buff *skb;
+ struct xenvif *vif = queue->vif;
- while (!kthread_should_stop()) {
- wait_event_interruptible(queue->wq,
- rx_work_todo(queue) ||
- queue->vif->disabled ||
- test_bit(QUEUE_STATUS_RX_PURGE_EVENT, &queue->status) ||
- kthread_should_stop());
+ for (;;) {
+ xenvif_wait_for_rx_work(queue);
if (kthread_should_stop())
break;
* context so we defer it here, if this thread is
* associated with queue 0.
*/
- if (unlikely(queue->vif->disabled && queue->id == 0)) {
- xenvif_carrier_off(queue->vif);
- } else if (unlikely(queue->vif->disabled)) {
- /* kthread_stop() would be called upon this thread soon,
- * be a bit proactive
- */
- skb_queue_purge(&queue->rx_queue);
- queue->rx_last_skb_slots = 0;
- } else if (unlikely(test_and_clear_bit(QUEUE_STATUS_RX_PURGE_EVENT,
- &queue->status))) {
- xenvif_rx_purge_event(queue);
- } else if (!netif_carrier_ok(queue->vif->dev)) {
- /* Another queue stalled and turned the carrier off, so
- * purge the internal queue of queues which were not
- * blocked
- */
- skb_queue_purge(&queue->rx_queue);
- queue->rx_last_skb_slots = 0;
+ if (unlikely(vif->disabled && queue->id == 0)) {
+ xenvif_carrier_off(vif);
+ xenvif_rx_queue_purge(queue);
+ continue;
}
if (!skb_queue_empty(&queue->rx_queue))
xenvif_rx_action(queue);
+ /* If the guest hasn't provided any Rx slots for a
+ * while it's probably not responsive, drop the
+ * carrier so packets are dropped earlier.
+ */
+ if (xenvif_rx_queue_stalled(queue))
+ xenvif_queue_carrier_off(queue);
+ else if (xenvif_rx_queue_ready(queue))
+ xenvif_queue_carrier_on(queue);
+
+ /* Queued packets may have foreign pages from other
+ * domains. These cannot be queued indefinitely as
+ * this would starve guests of grant refs and transmit
+ * slots.
+ */
+ xenvif_rx_queue_drop_expired(queue);
+
+ xenvif_rx_queue_maybe_wake(queue);
+
cond_resched();
}
/* Bin any remaining skbs */
- while ((skb = skb_dequeue(&queue->rx_queue)) != NULL)
- dev_kfree_skb(skb);
+ xenvif_rx_queue_purge(queue);
return 0;
}
goto failed_init;
rx_drain_timeout_jiffies = msecs_to_jiffies(rx_drain_timeout_msecs);
+ rx_stall_timeout_jiffies = msecs_to_jiffies(rx_stall_timeout_msecs);
#ifdef CONFIG_DEBUG_FS
xen_netback_dbg_root = debugfs_create_dir("xen-netback", NULL);
struct xenvif_queue *queue = m->private;
struct xen_netif_tx_back_ring *tx_ring = &queue->tx;
struct xen_netif_rx_back_ring *rx_ring = &queue->rx;
+ struct netdev_queue *dev_queue;
if (tx_ring->sring) {
struct xen_netif_tx_sring *sring = tx_ring->sring;
queue->credit_timeout.expires,
jiffies);
+ dev_queue = netdev_get_tx_queue(queue->vif->dev, queue->id);
+
+ seq_printf(m, "\nRx internal queue: len %u max %u pkts %u %s\n",
+ queue->rx_queue_len, queue->rx_queue_max,
+ skb_queue_len(&queue->rx_queue),
+ netif_tx_queue_stopped(dev_queue) ? "stopped" : "running");
+
return 0;
}
be->vif->queues = vzalloc(requested_num_queues *
sizeof(struct xenvif_queue));
be->vif->num_queues = requested_num_queues;
+ be->vif->stalled_queues = requested_num_queues;
for (queue_index = 0; queue_index < requested_num_queues; ++queue_index) {
queue = &be->vif->queues[queue_index];
if (!rx_copy)
return -EOPNOTSUPP;
- if (vif->dev->tx_queue_len != 0) {
- if (xenbus_scanf(XBT_NIL, dev->otherend,
- "feature-rx-notify", "%d", &val) < 0)
- val = 0;
- if (val)
- vif->can_queue = 1;
- else
- /* Must be non-zero for pfifo_fast to work. */
- vif->dev->tx_queue_len = 1;
+ if (xenbus_scanf(XBT_NIL, dev->otherend,
+ "feature-rx-notify", "%d", &val) < 0 || val == 0) {
+ xenbus_dev_fatal(dev, -EINVAL, "feature-rx-notify is mandatory");
+ return -EINVAL;
}
if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg",
* This function assign memory region pointed by "memory-region" device tree
* property to the given device.
*/
-void of_reserved_mem_device_init(struct device *dev)
+int of_reserved_mem_device_init(struct device *dev)
{
struct reserved_mem *rmem;
struct device_node *np;
+ int ret;
np = of_parse_phandle(dev->of_node, "memory-region", 0);
if (!np)
- return;
+ return -ENODEV;
rmem = __find_rmem(np);
of_node_put(np);
if (!rmem || !rmem->ops || !rmem->ops->device_init)
- return;
+ return -EINVAL;
+
+ ret = rmem->ops->device_init(rmem, dev);
+ if (ret == 0)
+ dev_info(dev, "assigned reserved memory node %s\n", rmem->name);
- rmem->ops->device_init(rmem, dev);
- dev_info(dev, "assigned reserved memory node %s\n", rmem->name);
+ return ret;
}
/**
goto err_pcie;
}
- /* allow the clocks to stabilize */
- usleep_range(200, 500);
-
/* power up core phy and enable ref clock */
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
IMX6Q_GPR1_PCIE_TEST_PD, 0 << 18);
+ /*
+ * the async reset input need ref clock to sync internally,
+ * when the ref clock comes after reset, internal synced
+ * reset time is too short, cannot meet the requirement.
+ * add one ~10us delay here.
+ */
+ udelay(10);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);
+ /* allow the clocks to stabilize */
+ usleep_range(200, 500);
+
/* Some boards don't have PCIe reset GPIO. */
if (gpio_is_valid(imx6_pcie->reset_gpio)) {
gpio_set_value(imx6_pcie->reset_gpio, 0);
goto err_out_none;
}
- if (!dev->port->subordinate) {
- /* Can happen if we run out of bus numbers during probe */
- dev_err(&dev->device,
- "Hotplug bridge without secondary bus, ignoring\n");
- goto err_out_none;
- }
-
ctrl = pcie_init(dev);
if (!ctrl) {
dev_err(&dev->device, "Controller initialization failed\n");
}
static DEVICE_ATTR_RO(modalias);
-static ssize_t enabled_store(struct device *dev, struct device_attribute *attr,
+static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct pci_dev *pdev = to_pci_dev(dev);
return result < 0 ? result : count;
}
-static ssize_t enabled_show(struct device *dev, struct device_attribute *attr,
+static ssize_t enable_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct pci_dev *pdev;
pdev = to_pci_dev(dev);
return sprintf(buf, "%u\n", atomic_read(&pdev->enable_cnt));
}
-static DEVICE_ATTR_RW(enabled);
+static DEVICE_ATTR_RW(enable);
#ifdef CONFIG_NUMA
static ssize_t numa_node_show(struct device *dev, struct device_attribute *attr,
#endif
&dev_attr_dma_mask_bits.attr,
&dev_attr_consistent_dma_mask_bits.attr,
- &dev_attr_enabled.attr,
+ &dev_attr_enable.attr,
&dev_attr_broken_parity_status.attr,
&dev_attr_msi_bus.attr,
#if defined(CONFIG_PM_RUNTIME) && defined(CONFIG_ACPI)
};
static const struct regulator_linear_range rk808_buck_voltage_ranges[] = {
- REGULATOR_LINEAR_RANGE(700000, 0, 63, 12500),
+ REGULATOR_LINEAR_RANGE(712500, 0, 63, 12500),
};
static const struct regulator_linear_range rk808_buck4_voltage_ranges[] = {
obj-$(CONFIG_RESET_CONTROLLER) += core.o
obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
+obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o
obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
obj-$(CONFIG_ARCH_STI) += sti/
--- /dev/null
+/*
+ * Copyright (C) 2014 Marvell Technology Group Ltd.
+ *
+ * Antoine Tenart <antoine.tenart@free-electrons.com>
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#define BERLIN_MAX_RESETS 32
+
+#define to_berlin_reset_priv(p) \
+ container_of((p), struct berlin_reset_priv, rcdev)
+
+struct berlin_reset_priv {
+ void __iomem *base;
+ unsigned int size;
+ struct reset_controller_dev rcdev;
+};
+
+static int berlin_reset_reset(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct berlin_reset_priv *priv = to_berlin_reset_priv(rcdev);
+ int offset = id >> 8;
+ int mask = BIT(id & 0x1f);
+
+ writel(mask, priv->base + offset);
+
+ /* let the reset be effective */
+ udelay(10);
+
+ return 0;
+}
+
+static struct reset_control_ops berlin_reset_ops = {
+ .reset = berlin_reset_reset,
+};
+
+static int berlin_reset_xlate(struct reset_controller_dev *rcdev,
+ const struct of_phandle_args *reset_spec)
+{
+ struct berlin_reset_priv *priv = to_berlin_reset_priv(rcdev);
+ unsigned offset, bit;
+
+ if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells))
+ return -EINVAL;
+
+ offset = reset_spec->args[0];
+ bit = reset_spec->args[1];
+
+ if (offset >= priv->size)
+ return -EINVAL;
+
+ if (bit >= BERLIN_MAX_RESETS)
+ return -EINVAL;
+
+ return (offset << 8) | bit;
+}
+
+static int __berlin_reset_init(struct device_node *np)
+{
+ struct berlin_reset_priv *priv;
+ struct resource res;
+ resource_size_t size;
+ int ret;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ ret = of_address_to_resource(np, 0, &res);
+ if (ret)
+ goto err;
+
+ size = resource_size(&res);
+ priv->base = ioremap(res.start, size);
+ if (!priv->base) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ priv->size = size;
+
+ priv->rcdev.owner = THIS_MODULE;
+ priv->rcdev.ops = &berlin_reset_ops;
+ priv->rcdev.of_node = np;
+ priv->rcdev.of_reset_n_cells = 2;
+ priv->rcdev.of_xlate = berlin_reset_xlate;
+
+ reset_controller_register(&priv->rcdev);
+
+ return 0;
+
+err:
+ kfree(priv);
+ return ret;
+}
+
+static const struct of_device_id berlin_reset_of_match[] __initconst = {
+ { .compatible = "marvell,berlin2-chip-ctrl" },
+ { .compatible = "marvell,berlin2cd-chip-ctrl" },
+ { .compatible = "marvell,berlin2q-chip-ctrl" },
+ { },
+};
+
+static int __init berlin_reset_init(void)
+{
+ struct device_node *np;
+ int ret;
+
+ for_each_matching_node(np, berlin_reset_of_match) {
+ ret = __berlin_reset_init(np);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+arch_initcall(berlin_reset_init);
config RTC_DRV_PM8XXX
tristate "Qualcomm PMIC8XXX RTC"
- depends on MFD_PM8XXX
+ depends on MFD_PM8XXX || MFD_SPMI_PMIC
help
If you say yes here you get support for the
Qualcomm PMIC8XXX RTC.
dev_err(dev, "bq32k: diode and resistor mismatch\n");
return -EINVAL;
}
- reg = 0x25;
+ reg = 0x45;
break;
default:
/* RTC_CTRL register bit fields */
#define PM8xxx_RTC_ENABLE BIT(7)
-#define PM8xxx_RTC_ALARM_ENABLE BIT(1)
#define PM8xxx_RTC_ALARM_CLEAR BIT(0)
#define NUM_8_BIT_RTC_REGS 0x4
+/**
+ * struct pm8xxx_rtc_regs - describe RTC registers per PMIC versions
+ * @ctrl: base address of control register
+ * @write: base address of write register
+ * @read: base address of read register
+ * @alarm_ctrl: base address of alarm control register
+ * @alarm_ctrl2: base address of alarm control2 register
+ * @alarm_rw: base address of alarm read-write register
+ * @alarm_en: alarm enable mask
+ */
+struct pm8xxx_rtc_regs {
+ unsigned int ctrl;
+ unsigned int write;
+ unsigned int read;
+ unsigned int alarm_ctrl;
+ unsigned int alarm_ctrl2;
+ unsigned int alarm_rw;
+ unsigned int alarm_en;
+};
+
/**
* struct pm8xxx_rtc - rtc driver internal structure
* @rtc: rtc device for this driver.
* @regmap: regmap used to access RTC registers
* @allow_set_time: indicates whether writing to the RTC is allowed
* @rtc_alarm_irq: rtc alarm irq number.
- * @rtc_base: address of rtc control register.
- * @rtc_read_base: base address of read registers.
- * @rtc_write_base: base address of write registers.
- * @alarm_rw_base: base address of alarm registers.
* @ctrl_reg: rtc control register.
* @rtc_dev: device structure.
* @ctrl_reg_lock: spinlock protecting access to ctrl_reg.
struct regmap *regmap;
bool allow_set_time;
int rtc_alarm_irq;
- int rtc_base;
- int rtc_read_base;
- int rtc_write_base;
- int alarm_rw_base;
- u8 ctrl_reg;
+ const struct pm8xxx_rtc_regs *regs;
struct device *rtc_dev;
spinlock_t ctrl_reg_lock;
};
{
int rc, i;
unsigned long secs, irq_flags;
- u8 value[NUM_8_BIT_RTC_REGS], alarm_enabled = 0, ctrl_reg;
+ u8 value[NUM_8_BIT_RTC_REGS], alarm_enabled = 0;
+ unsigned int ctrl_reg;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
+ const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
if (!rtc_dd->allow_set_time)
return -EACCES;
dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs);
spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
- ctrl_reg = rtc_dd->ctrl_reg;
- if (ctrl_reg & PM8xxx_RTC_ALARM_ENABLE) {
+ rc = regmap_read(rtc_dd->regmap, regs->ctrl, &ctrl_reg);
+ if (rc)
+ goto rtc_rw_fail;
+
+ if (ctrl_reg & regs->alarm_en) {
alarm_enabled = 1;
- ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE;
- rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg);
+ ctrl_reg &= ~regs->alarm_en;
+ rc = regmap_write(rtc_dd->regmap, regs->ctrl, ctrl_reg);
if (rc) {
dev_err(dev, "Write to RTC control register failed\n");
goto rtc_rw_fail;
}
- rtc_dd->ctrl_reg = ctrl_reg;
- } else {
- spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
}
/* Write 0 to Byte[0] */
- rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_write_base, 0);
+ rc = regmap_write(rtc_dd->regmap, regs->write, 0);
if (rc) {
dev_err(dev, "Write to RTC write data register failed\n");
goto rtc_rw_fail;
}
/* Write Byte[1], Byte[2], Byte[3] */
- rc = regmap_bulk_write(rtc_dd->regmap, rtc_dd->rtc_write_base + 1,
+ rc = regmap_bulk_write(rtc_dd->regmap, regs->write + 1,
&value[1], sizeof(value) - 1);
if (rc) {
dev_err(dev, "Write to RTC write data register failed\n");
}
/* Write Byte[0] */
- rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_write_base, value[0]);
+ rc = regmap_write(rtc_dd->regmap, regs->write, value[0]);
if (rc) {
dev_err(dev, "Write to RTC write data register failed\n");
goto rtc_rw_fail;
}
if (alarm_enabled) {
- ctrl_reg |= PM8xxx_RTC_ALARM_ENABLE;
- rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg);
+ ctrl_reg |= regs->alarm_en;
+ rc = regmap_write(rtc_dd->regmap, regs->ctrl, ctrl_reg);
if (rc) {
dev_err(dev, "Write to RTC control register failed\n");
goto rtc_rw_fail;
}
- rtc_dd->ctrl_reg = ctrl_reg;
}
rtc_rw_fail:
- if (alarm_enabled)
- spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
+ spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
return rc;
}
unsigned long secs;
unsigned int reg;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
+ const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
- rc = regmap_bulk_read(rtc_dd->regmap, rtc_dd->rtc_read_base,
- value, sizeof(value));
+ rc = regmap_bulk_read(rtc_dd->regmap, regs->read, value, sizeof(value));
if (rc) {
dev_err(dev, "RTC read data register failed\n");
return rc;
* Read the LSB again and check if there has been a carry over.
* If there is, redo the read operation.
*/
- rc = regmap_read(rtc_dd->regmap, rtc_dd->rtc_read_base, ®);
+ rc = regmap_read(rtc_dd->regmap, regs->read, ®);
if (rc < 0) {
dev_err(dev, "RTC read data register failed\n");
return rc;
}
if (unlikely(reg < value[0])) {
- rc = regmap_bulk_read(rtc_dd->regmap, rtc_dd->rtc_read_base,
+ rc = regmap_bulk_read(rtc_dd->regmap, regs->read,
value, sizeof(value));
if (rc) {
dev_err(dev, "RTC read data register failed\n");
static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
int rc, i;
- u8 value[NUM_8_BIT_RTC_REGS], ctrl_reg;
+ u8 value[NUM_8_BIT_RTC_REGS];
+ unsigned int ctrl_reg;
unsigned long secs, irq_flags;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
+ const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
rtc_tm_to_time(&alarm->time, &secs);
spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
- rc = regmap_bulk_write(rtc_dd->regmap, rtc_dd->alarm_rw_base, value,
+ rc = regmap_bulk_write(rtc_dd->regmap, regs->alarm_rw, value,
sizeof(value));
if (rc) {
dev_err(dev, "Write to RTC ALARM register failed\n");
goto rtc_rw_fail;
}
- ctrl_reg = rtc_dd->ctrl_reg;
+ rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg);
+ if (rc)
+ goto rtc_rw_fail;
if (alarm->enabled)
- ctrl_reg |= PM8xxx_RTC_ALARM_ENABLE;
+ ctrl_reg |= regs->alarm_en;
else
- ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE;
+ ctrl_reg &= ~regs->alarm_en;
- rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg);
+ rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
if (rc) {
- dev_err(dev, "Write to RTC control register failed\n");
+ dev_err(dev, "Write to RTC alarm control register failed\n");
goto rtc_rw_fail;
}
- rtc_dd->ctrl_reg = ctrl_reg;
-
dev_dbg(dev, "Alarm Set for h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n",
alarm->time.tm_hour, alarm->time.tm_min,
alarm->time.tm_sec, alarm->time.tm_mday,
u8 value[NUM_8_BIT_RTC_REGS];
unsigned long secs;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
+ const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
- rc = regmap_bulk_read(rtc_dd->regmap, rtc_dd->alarm_rw_base, value,
+ rc = regmap_bulk_read(rtc_dd->regmap, regs->alarm_rw, value,
sizeof(value));
if (rc) {
dev_err(dev, "RTC alarm time read failed\n");
int rc;
unsigned long irq_flags;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
- u8 ctrl_reg;
+ const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
+ unsigned int ctrl_reg;
spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
- ctrl_reg = rtc_dd->ctrl_reg;
+ rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg);
+ if (rc)
+ goto rtc_rw_fail;
if (enable)
- ctrl_reg |= PM8xxx_RTC_ALARM_ENABLE;
+ ctrl_reg |= regs->alarm_en;
else
- ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE;
+ ctrl_reg &= ~regs->alarm_en;
- rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg);
+ rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
if (rc) {
dev_err(dev, "Write to RTC control register failed\n");
goto rtc_rw_fail;
}
- rtc_dd->ctrl_reg = ctrl_reg;
-
rtc_rw_fail:
spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
return rc;
static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id)
{
struct pm8xxx_rtc *rtc_dd = dev_id;
+ const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
unsigned int ctrl_reg;
int rc;
unsigned long irq_flags;
spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
/* Clear the alarm enable bit */
- ctrl_reg = rtc_dd->ctrl_reg;
- ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE;
+ rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg);
+ if (rc) {
+ spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
+ goto rtc_alarm_handled;
+ }
+
+ ctrl_reg &= ~regs->alarm_en;
- rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg);
+ rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
if (rc) {
spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
dev_err(rtc_dd->rtc_dev,
- "Write to RTC control register failed\n");
+ "Write to alarm control register failed\n");
goto rtc_alarm_handled;
}
- rtc_dd->ctrl_reg = ctrl_reg;
spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
/* Clear RTC alarm register */
- rc = regmap_read(rtc_dd->regmap,
- rtc_dd->rtc_base + PM8XXX_ALARM_CTRL_OFFSET,
- &ctrl_reg);
+ rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl2, &ctrl_reg);
if (rc) {
dev_err(rtc_dd->rtc_dev,
- "RTC Alarm control register read failed\n");
+ "RTC Alarm control2 register read failed\n");
goto rtc_alarm_handled;
}
- ctrl_reg &= ~PM8xxx_RTC_ALARM_CLEAR;
- rc = regmap_write(rtc_dd->regmap,
- rtc_dd->rtc_base + PM8XXX_ALARM_CTRL_OFFSET,
- ctrl_reg);
+ ctrl_reg |= PM8xxx_RTC_ALARM_CLEAR;
+ rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl2, ctrl_reg);
if (rc)
dev_err(rtc_dd->rtc_dev,
- "Write to RTC Alarm control register failed\n");
+ "Write to RTC Alarm control2 register failed\n");
rtc_alarm_handled:
return IRQ_HANDLED;
}
+static int pm8xxx_rtc_enable(struct pm8xxx_rtc *rtc_dd)
+{
+ const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
+ unsigned int ctrl_reg;
+ int rc;
+
+ /* Check if the RTC is on, else turn it on */
+ rc = regmap_read(rtc_dd->regmap, regs->ctrl, &ctrl_reg);
+ if (rc)
+ return rc;
+
+ if (!(ctrl_reg & PM8xxx_RTC_ENABLE)) {
+ ctrl_reg |= PM8xxx_RTC_ENABLE;
+ rc = regmap_write(rtc_dd->regmap, regs->ctrl, ctrl_reg);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+static const struct pm8xxx_rtc_regs pm8921_regs = {
+ .ctrl = 0x11d,
+ .write = 0x11f,
+ .read = 0x123,
+ .alarm_rw = 0x127,
+ .alarm_ctrl = 0x11d,
+ .alarm_ctrl2 = 0x11e,
+ .alarm_en = BIT(1),
+};
+
+static const struct pm8xxx_rtc_regs pm8058_regs = {
+ .ctrl = 0x1e8,
+ .write = 0x1ea,
+ .read = 0x1ee,
+ .alarm_rw = 0x1f2,
+ .alarm_ctrl = 0x1e8,
+ .alarm_ctrl2 = 0x1e9,
+ .alarm_en = BIT(1),
+};
+
+static const struct pm8xxx_rtc_regs pm8941_regs = {
+ .ctrl = 0x6046,
+ .write = 0x6040,
+ .read = 0x6048,
+ .alarm_rw = 0x6140,
+ .alarm_ctrl = 0x6146,
+ .alarm_ctrl2 = 0x6148,
+ .alarm_en = BIT(7),
+};
+
/*
* Hardcoded RTC bases until IORESOURCE_REG mapping is figured out
*/
static const struct of_device_id pm8xxx_id_table[] = {
- { .compatible = "qcom,pm8921-rtc", .data = (void *) 0x11D },
- { .compatible = "qcom,pm8058-rtc", .data = (void *) 0x1E8 },
+ { .compatible = "qcom,pm8921-rtc", .data = &pm8921_regs },
+ { .compatible = "qcom,pm8058-rtc", .data = &pm8058_regs },
+ { .compatible = "qcom,pm8941-rtc", .data = &pm8941_regs },
{ },
};
MODULE_DEVICE_TABLE(of, pm8xxx_id_table);
static int pm8xxx_rtc_probe(struct platform_device *pdev)
{
int rc;
- unsigned int ctrl_reg;
struct pm8xxx_rtc *rtc_dd;
const struct of_device_id *match;
rtc_dd->allow_set_time = of_property_read_bool(pdev->dev.of_node,
"allow-set-time");
- rtc_dd->rtc_base = (long) match->data;
-
- /* Setup RTC register addresses */
- rtc_dd->rtc_write_base = rtc_dd->rtc_base + PM8XXX_RTC_WRITE_OFFSET;
- rtc_dd->rtc_read_base = rtc_dd->rtc_base + PM8XXX_RTC_READ_OFFSET;
- rtc_dd->alarm_rw_base = rtc_dd->rtc_base + PM8XXX_ALARM_RW_OFFSET;
-
+ rtc_dd->regs = match->data;
rtc_dd->rtc_dev = &pdev->dev;
- /* Check if the RTC is on, else turn it on */
- rc = regmap_read(rtc_dd->regmap, rtc_dd->rtc_base, &ctrl_reg);
- if (rc) {
- dev_err(&pdev->dev, "RTC control register read failed!\n");
+ rc = pm8xxx_rtc_enable(rtc_dd);
+ if (rc)
return rc;
- }
-
- if (!(ctrl_reg & PM8xxx_RTC_ENABLE)) {
- ctrl_reg |= PM8xxx_RTC_ENABLE;
- rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg);
- if (rc) {
- dev_err(&pdev->dev,
- "Write to RTC control register failed\n");
- return rc;
- }
- }
-
- rtc_dd->ctrl_reg = ctrl_reg;
platform_set_drvdata(pdev, rtc_dd);
}
clk_prepare_enable(info->rtc_clk);
- info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src");
- if (IS_ERR(info->rtc_src_clk)) {
- dev_err(&pdev->dev, "failed to find rtc source clock\n");
- return PTR_ERR(info->rtc_src_clk);
+ if (info->data->needs_src_clk) {
+ info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src");
+ if (IS_ERR(info->rtc_src_clk)) {
+ dev_err(&pdev->dev,
+ "failed to find rtc source clock\n");
+ return PTR_ERR(info->rtc_src_clk);
+ }
+ clk_prepare_enable(info->rtc_src_clk);
}
- clk_prepare_enable(info->rtc_src_clk);
-
/* check to see if everything is setup correctly */
if (info->data->enable)
* If the source port is outside our allocation range, the caller is
* responsible for keeping track of their port usage.
*/
+
+static struct cxgbi_sock *find_sock_on_port(struct cxgbi_device *cdev,
+ unsigned char port_id)
+{
+ struct cxgbi_ports_map *pmap = &cdev->pmap;
+ unsigned int i;
+ unsigned int used;
+
+ if (!pmap->max_connect || !pmap->used)
+ return NULL;
+
+ spin_lock_bh(&pmap->lock);
+ used = pmap->used;
+ for (i = 0; used && i < pmap->max_connect; i++) {
+ struct cxgbi_sock *csk = pmap->port_csk[i];
+
+ if (csk) {
+ if (csk->port_id == port_id) {
+ spin_unlock_bh(&pmap->lock);
+ return csk;
+ }
+ used--;
+ }
+ }
+ spin_unlock_bh(&pmap->lock);
+
+ return NULL;
+}
+
static int sock_get_port(struct cxgbi_sock *csk)
{
struct cxgbi_device *cdev = csk->cdev;
csk->daddr6.sin6_addr = daddr6->sin6_addr;
csk->daddr6.sin6_port = daddr6->sin6_port;
csk->daddr6.sin6_family = daddr6->sin6_family;
+ csk->saddr6.sin6_family = daddr6->sin6_family;
csk->saddr6.sin6_addr = pref_saddr;
neigh_release(n);
break;
case ISCSI_HOST_PARAM_IPADDRESS:
{
- __be32 addr;
-
- addr = cxgbi_get_iscsi_ipv4(chba);
- len = sprintf(buf, "%pI4", &addr);
+ struct cxgbi_sock *csk = find_sock_on_port(chba->cdev,
+ chba->port_id);
+ if (csk) {
+ len = sprintf(buf, "%pIS",
+ (struct sockaddr *)&csk->saddr);
+ }
log_debug(1 << CXGBI_DBG_ISCSI,
- "hba %s, ipv4 %pI4.\n", chba->ndev->name, &addr);
+ "hba %s, addr %s.\n", chba->ndev->name, buf);
break;
}
default:
chba->ndev->name);
}
-static inline __be32 cxgbi_get_iscsi_ipv4(struct cxgbi_hba *chba)
-{
- return chba->ipv4addr;
-}
-
struct cxgbi_device *cxgbi_device_register(unsigned int, unsigned int);
void cxgbi_device_unregister(struct cxgbi_device *);
void cxgbi_device_unregister_all(unsigned int flag);
blk_mq_start_request(req);
}
+ if (blk_queue_tagged(q))
+ req->cmd_flags |= REQ_QUEUED;
+ else
+ req->cmd_flags &= ~REQ_QUEUED;
+
scsi_init_cmd_errh(cmd);
cmd->scsi_done = scsi_mq_done;
list_for_each_entry(region, &kdev->regions, list)
#define first_region(kdev) \
- list_first_entry(&kdev->regions, \
- struct knav_region, list)
+ list_first_entry_or_null(&kdev->regions, \
+ struct knav_region, list)
#define for_each_queue_range(kdev, range) \
list_for_each_entry(range, &kdev->queue_ranges, list)
#define first_queue_range(kdev) \
- list_first_entry(&kdev->queue_ranges, \
- struct knav_range_info, list)
+ list_first_entry_or_null(&kdev->queue_ranges, \
+ struct knav_range_info, list)
#define for_each_pool(kdev, pool) \
list_for_each_entry(pool, &kdev->pools, list)
dev_err(kdev->dev, "out of descs in region(%d) for pool(%s)\n",
region_id, name);
ret = -ENOMEM;
- goto err;
+ goto err_unlock;
}
/* Region maintains a sorted (by region offset) list of pools
dev_err(kdev->dev, "pool(%s) create failed: fragmented desc pool in region(%d)\n",
name, region_id);
ret = -ENOMEM;
- goto err;
+ goto err_unlock;
}
mutex_unlock(&knav_dev_lock);
kdesc_fill_pool(pool);
return pool;
-err:
+err_unlock:
mutex_unlock(&knav_dev_lock);
+err:
kfree(pool->name);
devm_kfree(kdev->dev, pool);
return ERR_PTR(ret);
static void knav_queue_free_regions(struct knav_device *kdev)
{
struct knav_region *region;
- struct knav_pool *pool;
+ struct knav_pool *pool, *tmp;
unsigned size;
for (;;) {
region = first_region(kdev);
if (!region)
break;
- list_for_each_entry(pool, ®ion->pools, region_inst)
+ list_for_each_entry_safe(pool, tmp, ®ion->pools, region_inst)
knav_pool_destroy(pool);
size = region->virt_end - region->virt_start;
size = (1 << kdev->inst_shift) * kdev->num_queues_in_use;
kdev->instances = devm_kzalloc(kdev->dev, size, GFP_KERNEL);
if (!kdev->instances)
- return -1;
+ return -ENOMEM;
for_each_queue_range(kdev, range) {
if (range->ops && range->ops->init_range)
master->cleanup = dw_spi_cleanup;
master->transfer_one_message = dw_spi_transfer_one_message;
master->max_speed_hz = dws->max_freq;
+ master->dev.of_node = dev->of_node;
/* Basic HW init */
spi_hw_init(dws);
spi->master = master;
of_id = of_match_device(orion_spi_of_match_table, &pdev->dev);
- devdata = of_id->data;
+ devdata = (of_id) ? of_id->data : &orion_spi_dev_data;
spi->devdata = devdata;
spi->clk = devm_clk_get(&pdev->dev, NULL);
pl022->sgt_tx.nents, DMA_TO_DEVICE);
err_tx_sgmap:
dma_unmap_sg(rxchan->device->dev, pl022->sgt_rx.sgl,
- pl022->sgt_tx.nents, DMA_FROM_DEVICE);
+ pl022->sgt_rx.nents, DMA_FROM_DEVICE);
err_rx_sgmap:
sg_free_table(&pl022->sgt_tx);
err_alloc_tx_sg:
#define RXBUSY (1 << 0)
#define TXBUSY (1 << 1)
+/* sclk_out: spi master internal logic in rk3x can support 50Mhz */
+#define MAX_SCLK_OUT 50000000
+
enum rockchip_ssi_type {
SSI_MOTO_SPI = 0,
SSI_TI_SSP,
spin_unlock_irqrestore(&rs->lock, flags);
+ spi_enable_chip(rs, 0);
+
return 0;
}
if (rs->tx)
wait_for_idle(rs);
+ spi_enable_chip(rs, 0);
+
return 0;
}
spin_lock_irqsave(&rs->lock, flags);
rs->state &= ~RXBUSY;
- if (!(rs->state & TXBUSY))
+ if (!(rs->state & TXBUSY)) {
+ spi_enable_chip(rs, 0);
spi_finalize_current_transfer(rs->master);
+ }
spin_unlock_irqrestore(&rs->lock, flags);
}
spin_lock_irqsave(&rs->lock, flags);
rs->state &= ~TXBUSY;
- if (!(rs->state & RXBUSY))
+ if (!(rs->state & RXBUSY)) {
+ spi_enable_chip(rs, 0);
spi_finalize_current_transfer(rs->master);
+ }
spin_unlock_irqrestore(&rs->lock, flags);
}
dmacr |= RF_DMA_EN;
}
+ if (WARN_ON(rs->speed > MAX_SCLK_OUT))
+ rs->speed = MAX_SCLK_OUT;
+
+ /* the minimum divsor is 2 */
+ if (rs->max_freq < 2 * rs->speed) {
+ clk_set_rate(rs->spiclk, 2 * rs->speed);
+ rs->max_freq = clk_get_rate(rs->spiclk);
+ }
+
/* div doesn't support odd number */
div = max_t(u32, rs->max_freq / rs->speed, 1);
div = (div + 1) & 0xfffe;
- spi_enable_chip(rs, 0);
-
writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0);
writel_relaxed(rs->len - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
spi_set_clk(rs, div);
dev_dbg(rs->dev, "cr0 0x%x, div %d\n", cr0, div);
-
- spi_enable_chip(rs, 1);
}
static int rockchip_spi_transfer_one(
struct spi_device *spi,
struct spi_transfer *xfer)
{
- int ret = 0;
+ int ret = 1;
struct rockchip_spi *rs = spi_master_get_devdata(master);
WARN_ON(readl_relaxed(rs->regs + ROCKCHIP_SPI_SSIENR) &&
rs->tmode = CR0_XFM_RO;
/* we need prepare dma before spi was enabled */
- if (master->can_dma && master->can_dma(master, spi, xfer)) {
+ if (master->can_dma && master->can_dma(master, spi, xfer))
rs->use_dma = 1;
- rockchip_spi_prepare_dma(rs);
- } else {
+ else
rs->use_dma = 0;
- }
rockchip_spi_config(rs);
- if (!rs->use_dma)
+ if (rs->use_dma) {
+ if (rs->tmode == CR0_XFM_RO) {
+ /* rx: dma must be prepared first */
+ rockchip_spi_prepare_dma(rs);
+ spi_enable_chip(rs, 1);
+ } else {
+ /* tx or tr: spi must be enabled first */
+ spi_enable_chip(rs, 1);
+ rockchip_spi_prepare_dma(rs);
+ }
+ } else {
+ spi_enable_chip(rs, 1);
ret = rockchip_spi_pio_transfer(rs);
+ }
return ret;
}
struct spi_device *spi;
struct list_head device_entry;
- /* buffer is NULL unless this device is open (users > 0) */
+ /* TX/RX buffers are NULL unless this device is open (users > 0) */
struct mutex buf_lock;
unsigned users;
- u8 *buffer;
+ u8 *tx_buffer;
+ u8 *rx_buffer;
};
static LIST_HEAD(device_list);
spidev_sync_write(struct spidev_data *spidev, size_t len)
{
struct spi_transfer t = {
- .tx_buf = spidev->buffer,
+ .tx_buf = spidev->tx_buffer,
.len = len,
};
struct spi_message m;
spidev_sync_read(struct spidev_data *spidev, size_t len)
{
struct spi_transfer t = {
- .rx_buf = spidev->buffer,
+ .rx_buf = spidev->rx_buffer,
.len = len,
};
struct spi_message m;
if (status > 0) {
unsigned long missing;
- missing = copy_to_user(buf, spidev->buffer, status);
+ missing = copy_to_user(buf, spidev->rx_buffer, status);
if (missing == status)
status = -EFAULT;
else
spidev = filp->private_data;
mutex_lock(&spidev->buf_lock);
- missing = copy_from_user(spidev->buffer, buf, count);
+ missing = copy_from_user(spidev->tx_buffer, buf, count);
if (missing == 0)
status = spidev_sync_write(spidev, count);
else
struct spi_transfer *k_tmp;
struct spi_ioc_transfer *u_tmp;
unsigned n, total;
- u8 *buf;
+ u8 *tx_buf, *rx_buf;
int status = -EFAULT;
spi_message_init(&msg);
* We walk the array of user-provided transfers, using each one
* to initialize a kernel version of the same transfer.
*/
- buf = spidev->buffer;
+ tx_buf = spidev->tx_buffer;
+ rx_buf = spidev->rx_buffer;
total = 0;
for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;
n;
}
if (u_tmp->rx_buf) {
- k_tmp->rx_buf = buf;
+ k_tmp->rx_buf = rx_buf;
if (!access_ok(VERIFY_WRITE, (u8 __user *)
(uintptr_t) u_tmp->rx_buf,
u_tmp->len))
goto done;
}
if (u_tmp->tx_buf) {
- k_tmp->tx_buf = buf;
- if (copy_from_user(buf, (const u8 __user *)
+ k_tmp->tx_buf = tx_buf;
+ if (copy_from_user(tx_buf, (const u8 __user *)
(uintptr_t) u_tmp->tx_buf,
u_tmp->len))
goto done;
}
- buf += k_tmp->len;
+ tx_buf += k_tmp->len;
+ rx_buf += k_tmp->len;
k_tmp->cs_change = !!u_tmp->cs_change;
k_tmp->tx_nbits = u_tmp->tx_nbits;
goto done;
/* copy any rx data out of bounce buffer */
- buf = spidev->buffer;
+ rx_buf = spidev->rx_buffer;
for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {
if (u_tmp->rx_buf) {
if (__copy_to_user((u8 __user *)
- (uintptr_t) u_tmp->rx_buf, buf,
+ (uintptr_t) u_tmp->rx_buf, rx_buf,
u_tmp->len)) {
status = -EFAULT;
goto done;
}
}
- buf += u_tmp->len;
+ rx_buf += u_tmp->len;
}
status = total;
break;
}
}
- if (status == 0) {
- if (!spidev->buffer) {
- spidev->buffer = kmalloc(bufsiz, GFP_KERNEL);
- if (!spidev->buffer) {
+
+ if (status) {
+ pr_debug("spidev: nothing for minor %d\n", iminor(inode));
+ goto err_find_dev;
+ }
+
+ if (!spidev->tx_buffer) {
+ spidev->tx_buffer = kmalloc(bufsiz, GFP_KERNEL);
+ if (!spidev->tx_buffer) {
dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");
status = -ENOMEM;
+ goto err_find_dev;
}
}
- if (status == 0) {
- spidev->users++;
- filp->private_data = spidev;
- nonseekable_open(inode, filp);
+
+ if (!spidev->rx_buffer) {
+ spidev->rx_buffer = kmalloc(bufsiz, GFP_KERNEL);
+ if (!spidev->rx_buffer) {
+ dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");
+ status = -ENOMEM;
+ goto err_alloc_rx_buf;
}
- } else
- pr_debug("spidev: nothing for minor %d\n", iminor(inode));
+ }
+
+ spidev->users++;
+ filp->private_data = spidev;
+ nonseekable_open(inode, filp);
+
+ mutex_unlock(&device_list_lock);
+ return 0;
+err_alloc_rx_buf:
+ kfree(spidev->tx_buffer);
+ spidev->tx_buffer = NULL;
+err_find_dev:
mutex_unlock(&device_list_lock);
return status;
}
if (!spidev->users) {
int dofree;
- kfree(spidev->buffer);
- spidev->buffer = NULL;
+ kfree(spidev->tx_buffer);
+ spidev->tx_buffer = NULL;
+
+ kfree(spidev->rx_buffer);
+ spidev->rx_buffer = NULL;
/* ... after we unbound from the underlying device? */
spin_lock_irq(&spidev->spi_lock);
struct logger_log *log = file_get_log(iocb->ki_filp);
struct logger_entry header;
struct timespec now;
- size_t len, count;
+ size_t len, count, w_off;
count = min_t(size_t, iocb->ki_nbytes, LOGGER_ENTRY_MAX_PAYLOAD);
memcpy(log->buffer + log->w_off, &header, len);
memcpy(log->buffer, (char *)&header + len, sizeof(header) - len);
- len = min(count, log->size - log->w_off);
+ /* Work with a copy until we are ready to commit the whole entry */
+ w_off = logger_offset(log, log->w_off + sizeof(struct logger_entry));
- if (copy_from_iter(log->buffer + log->w_off, len, from) != len) {
+ len = min(count, log->size - w_off);
+
+ if (copy_from_iter(log->buffer + w_off, len, from) != len) {
/*
- * Note that by not updating w_off, this abandons the
+ * Note that by not updating log->w_off, this abandons the
* portion of the new entry that *was* successfully
* copied, just above. This is intentional to avoid
* message corruption from missing fragments.
return -EFAULT;
}
- log->w_off = logger_offset(log, log->w_off + count);
+ log->w_off = logger_offset(log, w_off + count);
mutex_unlock(&log->mutex);
/* wake up any blocked readers */
config COMEDI_II_PCI20KC
tristate "Intelligent Instruments PCI-20001C carrier support"
+ depends on HAS_IOMEM
---help---
Enable support for Intelligent Instruments PCI-20001C carrier
PCI-20001, PCI-20006 and PCI-20341
config COMEDI_ADDI_APCI_3120
tristate "ADDI-DATA APCI_3120/3001 support"
depends on HAS_DMA
- depends on VIRT_TO_BUS
---help---
Enable support for ADDI-DATA APCI_3120/3001 cards
unsigned int *chanlist;
int ret;
- /* user_chanlist could be NULL for do_cmdtest ioctls */
- if (!user_chanlist)
- return 0;
-
+ cmd->chanlist = NULL;
chanlist = memdup_user(user_chanlist,
cmd->chanlist_len * sizeof(unsigned int));
if (IS_ERR(chanlist))
s = &dev->subdevices[cmd.subdev];
- /* load channel/gain list */
- ret = __comedi_get_user_chanlist(dev, s, user_chanlist, &cmd);
- if (ret)
- return ret;
+ /* user_chanlist can be NULL for COMEDI_CMDTEST ioctl */
+ if (user_chanlist) {
+ /* load channel/gain list */
+ ret = __comedi_get_user_chanlist(dev, s, user_chanlist, &cmd);
+ if (ret)
+ return ret;
+ }
ret = s->do_cmdtest(dev, s, &cmd);
+ kfree(cmd.chanlist); /* free kernel copy of user chanlist */
+
/* restore chanlist pointer before copying back */
cmd.chanlist = (unsigned int __force *)user_chanlist;
*/
-static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
+static int do_lock_ioctl(struct comedi_device *dev, unsigned long arg,
void *file)
{
int ret = 0;
This function isn't protected by the semaphore, since
we already own the lock.
*/
-static int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
+static int do_unlock_ioctl(struct comedi_device *dev, unsigned long arg,
void *file)
{
struct comedi_subdevice *s;
nothing
*/
-static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
+static int do_cancel_ioctl(struct comedi_device *dev, unsigned long arg,
void *file)
{
struct comedi_subdevice *s;
nothing
*/
-static int do_poll_ioctl(struct comedi_device *dev, unsigned int arg,
+static int do_poll_ioctl(struct comedi_device *dev, unsigned long arg,
void *file)
{
struct comedi_subdevice *s;
/* Grab all IRQ sources */
for (i = 0; i < of_cfg->irq_count; i++) {
lradc->irq[i] = platform_get_irq(pdev, i);
- if (lradc->irq[i] < 0)
- return lradc->irq[i];
+ if (lradc->irq[i] < 0) {
+ ret = lradc->irq[i];
+ goto err_clk;
+ }
ret = devm_request_irq(dev, lradc->irq[i],
mxs_lradc_handle_irq, 0,
of_cfg->irq_name[i], iio);
if (ret)
- return ret;
+ goto err_clk;
}
lradc->vref_mv = of_cfg->vref_mv;
&mxs_lradc_trigger_handler,
&mxs_lradc_buffer_ops);
if (ret)
- return ret;
+ goto err_clk;
ret = mxs_lradc_trigger_init(iio);
if (ret)
mxs_lradc_trigger_remove(iio);
err_trig:
iio_triggered_buffer_cleanup(iio);
+err_clk:
+ clk_disable_unprepare(lradc->clk);
return ret;
}
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.address = AD5933_REG_TEMP_DATA,
+ .scan_index = -1,
.scan_type = {
.sign = 's',
.realbits = 14,
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
- .extend_name = "real_raw",
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
- BIT(IIO_CHAN_INFO_SCALE),
+ .extend_name = "real",
.address = AD5933_REG_REAL_DATA,
.scan_index = 0,
.scan_type = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
- .extend_name = "imag_raw",
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
- BIT(IIO_CHAN_INFO_SCALE),
+ .extend_name = "imag",
.address = AD5933_REG_IMAG_DATA,
.scan_index = 1,
.scan_type = {
indio_dev->name = id->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ad5933_channels;
- indio_dev->num_channels = 1; /* only register temp0_input */
+ indio_dev->num_channels = ARRAY_SIZE(ad5933_channels);
ret = ad5933_register_ring_funcs_and_init(indio_dev);
if (ret)
goto error_disable_reg;
- /* skip temp0_input, register in0_(real|imag)_raw */
- ret = iio_buffer_register(indio_dev, &ad5933_channels[1], 2);
+ ret = iio_buffer_register(indio_dev, ad5933_channels,
+ ARRAY_SIZE(ad5933_channels));
if (ret)
goto error_unreg_ring;
};
struct eeprom_priv {
+ u8 mac_addr[6]; /* PermanentAddress */
u8 bautoload_fail_flag;
u8 bloadfile_fail_flag;
u8 bloadmac_fail_flag;
/* u8 bempty; */
/* u8 sys_config; */
- u8 mac_addr[6]; /* PermanentAddress */
/* u8 config0; */
u16 channel_plan;
/* u8 country_string[3]; */
ci_role_destroy(ci);
ci_hdrc_enter_lpm(ci, true);
usb_phy_shutdown(ci->transceiver);
- kfree(ci->hw_bank.regmap);
return 0;
}
unsigned port_suspend_change:1;
unsigned port_over_current_change:1;
unsigned port_l1_change:1;
- unsigned reserved:26;
+ unsigned reserved:25;
} b;
} flags;
hs_ep->fifo_size = val;
break;
}
- if (i == 8)
- return -ENOMEM;
+ if (i == 8) {
+ ret = -ENOMEM;
+ goto error;
+ }
}
/* for non control endpoints, set PID to D0 */
/* enable the endpoint interrupt */
s3c_hsotg_ctrl_epint(hsotg, index, dir_in, 1);
+error:
spin_unlock_irqrestore(&hsotg->lock, flags);
return ret;
}
spin_lock_irqsave(&hsotg->lock, flags);
- if (!driver)
- hsotg->driver = NULL;
-
+ hsotg->driver = NULL;
hsotg->gadget.speed = USB_SPEED_UNKNOWN;
spin_unlock_irqrestore(&hsotg->lock, flags);
s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum);
/* disable power and clock */
+ s3c_hsotg_phy_disable(hsotg);
ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
hsotg->supplies);
goto err_ep_mem;
}
- s3c_hsotg_phy_disable(hsotg);
-
ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget);
if (ret)
goto err_ep_mem;
{
struct dwc3_omap *omap = dev_get_drvdata(dev);
- dwc3_omap_write_irqmisc_set(omap, 0x00);
+ dwc3_omap_disable_irqs(omap);
return 0;
}
static void dwc3_omap_complete(struct device *dev)
{
struct dwc3_omap *omap = dev_get_drvdata(dev);
- u32 reg;
- reg = (USBOTGSS_IRQMISC_OEVT |
- USBOTGSS_IRQMISC_DRVVBUS_RISE |
- USBOTGSS_IRQMISC_CHRGVBUS_RISE |
- USBOTGSS_IRQMISC_DISCHRGVBUS_RISE |
- USBOTGSS_IRQMISC_IDPULLUP_RISE |
- USBOTGSS_IRQMISC_DRVVBUS_FALL |
- USBOTGSS_IRQMISC_CHRGVBUS_FALL |
- USBOTGSS_IRQMISC_DISCHRGVBUS_FALL |
- USBOTGSS_IRQMISC_IDPULLUP_FALL);
-
- dwc3_omap_write_irqmisc_set(omap, reg);
+ dwc3_omap_enable_irqs(omap);
}
static int dwc3_omap_suspend(struct device *dev)
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
#define PCI_DEVICE_ID_INTEL_BYT 0x0f37
#define PCI_DEVICE_ID_INTEL_MRFLD 0x119e
+#define PCI_DEVICE_ID_INTEL_BSW 0x22B7
struct dwc3_pci {
struct device *dev;
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
},
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), },
{ } /* Terminating Entry */
/* stall is always issued on EP0 */
dep = dwc->eps[0];
- __dwc3_gadget_ep_set_halt(dep, 1);
+ __dwc3_gadget_ep_set_halt(dep, 1, false);
dep->flags = DWC3_EP_ENABLED;
dwc->delayed_status = false;
dwc3_ep0_out_start(dwc);
}
-int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
+int __dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
{
struct dwc3_ep *dep = to_dwc3_ep(ep);
struct dwc3 *dwc = dep->dwc;
return 0;
}
+int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
+{
+ struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ ret = __dwc3_gadget_ep0_set_halt(ep, value);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
+}
+
void dwc3_ep0_out_start(struct dwc3 *dwc)
{
int ret;
return -EINVAL;
if (set == 0 && (dep->flags & DWC3_EP_WEDGE))
break;
- ret = __dwc3_gadget_ep_set_halt(dep, set);
+ ret = __dwc3_gadget_ep_set_halt(dep, set, true);
if (ret)
return -EINVAL;
break;
dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
- r = next_request(&ep0->request_list);
- ur = &r->request;
-
trb = dwc->ep0_trb;
status = DWC3_TRB_SIZE_TRBSTS(trb->size);
return;
}
+ r = next_request(&ep0->request_list);
+ if (!r)
+ return;
+
+ ur = &r->request;
+
length = trb->size & DWC3_TRB_SIZE_MASK;
if (dwc->ep0_bounced) {
dwc3_ep0_stall_and_restart(dwc);
} else {
- /*
- * handle the case where we have to send a zero packet. This
- * seems to be case when req.length > maxpacket. Could it be?
- */
- if (r)
- dwc3_gadget_giveback(ep0, r, 0);
+ dwc3_gadget_giveback(ep0, r, 0);
+
+ if (IS_ALIGNED(ur->length, ep0->endpoint.maxpacket) &&
+ ur->length && ur->zero) {
+ int ret;
+
+ dwc->ep0_next_event = DWC3_EP0_COMPLETE;
+
+ ret = dwc3_ep0_start_trans(dwc, epnum,
+ dwc->ctrl_req_addr, 0,
+ DWC3_TRBCTL_CONTROL_DATA);
+ WARN_ON(ret < 0);
+ }
}
}
if (!usb_endpoint_xfer_isoc(desc))
return 0;
- memset(&trb_link, 0, sizeof(trb_link));
-
/* Link TRB for ISOC. The HWO bit is never reset */
trb_st_hw = &dep->trb_pool[0];
trb_link = &dep->trb_pool[DWC3_TRB_NUM - 1];
+ memset(trb_link, 0, sizeof(*trb_link));
trb_link->bpl = lower_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw));
trb_link->bph = upper_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw));
/* make sure HW endpoint isn't stalled */
if (dep->flags & DWC3_EP_STALL)
- __dwc3_gadget_ep_set_halt(dep, 0);
+ __dwc3_gadget_ep_set_halt(dep, 0, false);
reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
reg &= ~DWC3_DALEPENA_EP(dep->number);
return ret;
}
-int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value)
+int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)
{
struct dwc3_gadget_ep_cmd_params params;
struct dwc3 *dwc = dep->dwc;
int ret;
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
+ dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name);
+ return -EINVAL;
+ }
+
memset(¶ms, 0x00, sizeof(params));
if (value) {
+ if (!protocol && ((dep->direction && dep->flags & DWC3_EP_BUSY) ||
+ (!list_empty(&dep->req_queued) ||
+ !list_empty(&dep->request_list)))) {
+ dev_dbg(dwc->dev, "%s: pending request, cannot halt\n",
+ dep->name);
+ return -EAGAIN;
+ }
+
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
DWC3_DEPCMD_SETSTALL, ¶ms);
if (ret)
int ret;
spin_lock_irqsave(&dwc->lock, flags);
-
- if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
- dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name);
- ret = -EINVAL;
- goto out;
- }
-
- ret = __dwc3_gadget_ep_set_halt(dep, value);
-out:
+ ret = __dwc3_gadget_ep_set_halt(dep, value, false);
spin_unlock_irqrestore(&dwc->lock, flags);
return ret;
struct dwc3_ep *dep = to_dwc3_ep(ep);
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
+ int ret;
spin_lock_irqsave(&dwc->lock, flags);
dep->flags |= DWC3_EP_WEDGE;
- spin_unlock_irqrestore(&dwc->lock, flags);
if (dep->number == 0 || dep->number == 1)
- return dwc3_gadget_ep0_set_halt(ep, 1);
+ ret = __dwc3_gadget_ep0_set_halt(ep, 1);
else
- return dwc3_gadget_ep_set_halt(ep, 1);
+ ret = __dwc3_gadget_ep_set_halt(dep, 1, false);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
}
/* -------------------------------------------------------------------------- */
void dwc3_ep0_interrupt(struct dwc3 *dwc,
const struct dwc3_event_depevt *event);
void dwc3_ep0_out_start(struct dwc3 *dwc);
+int __dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value);
int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value);
int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
gfp_t gfp_flags);
-int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
+int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol);
/**
* dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
TP_PROTO(struct usb_ctrlrequest *ctrl),
TP_ARGS(ctrl),
TP_STRUCT__entry(
- __field(struct usb_ctrlrequest *, ctrl)
+ __field(__u8, bRequestType)
+ __field(__u8, bRequest)
+ __field(__le16, wValue)
+ __field(__le16, wIndex)
+ __field(__le16, wLength)
),
TP_fast_assign(
- __entry->ctrl = ctrl;
+ __entry->bRequestType = ctrl->bRequestType;
+ __entry->bRequest = ctrl->bRequest;
+ __entry->wValue = ctrl->wValue;
+ __entry->wIndex = ctrl->wIndex;
+ __entry->wLength = ctrl->wLength;
),
TP_printk("bRequestType %02x bRequest %02x wValue %04x wIndex %04x wLength %d",
- __entry->ctrl->bRequestType, __entry->ctrl->bRequest,
- le16_to_cpu(__entry->ctrl->wValue), le16_to_cpu(__entry->ctrl->wIndex),
- le16_to_cpu(__entry->ctrl->wLength)
+ __entry->bRequestType, __entry->bRequest,
+ le16_to_cpu(__entry->wValue), le16_to_cpu(__entry->wIndex),
+ le16_to_cpu(__entry->wLength)
)
);
TP_PROTO(struct dwc3_request *req),
TP_ARGS(req),
TP_STRUCT__entry(
+ __dynamic_array(char, name, DWC3_MSG_MAX)
__field(struct dwc3_request *, req)
+ __field(unsigned, actual)
+ __field(unsigned, length)
+ __field(int, status)
),
TP_fast_assign(
+ snprintf(__get_str(name), DWC3_MSG_MAX, "%s", req->dep->name);
__entry->req = req;
+ __entry->actual = req->request.actual;
+ __entry->length = req->request.length;
+ __entry->status = req->request.status;
),
TP_printk("%s: req %p length %u/%u ==> %d",
- __entry->req->dep->name, __entry->req,
- __entry->req->request.actual, __entry->req->request.length,
- __entry->req->request.status
+ __get_str(name), __entry->req, __entry->actual, __entry->length,
+ __entry->status
)
);
struct dwc3_gadget_ep_cmd_params *params),
TP_ARGS(dep, cmd, params),
TP_STRUCT__entry(
- __field(struct dwc3_ep *, dep)
+ __dynamic_array(char, name, DWC3_MSG_MAX)
__field(unsigned int, cmd)
__field(struct dwc3_gadget_ep_cmd_params *, params)
),
TP_fast_assign(
- __entry->dep = dep;
+ snprintf(__get_str(name), DWC3_MSG_MAX, "%s", dep->name);
__entry->cmd = cmd;
__entry->params = params;
),
TP_printk("%s: cmd '%s' [%d] params %08x %08x %08x\n",
- __entry->dep->name, dwc3_gadget_ep_cmd_string(__entry->cmd),
+ __get_str(name), dwc3_gadget_ep_cmd_string(__entry->cmd),
__entry->cmd, __entry->params->param0,
__entry->params->param1, __entry->params->param2
)
TP_PROTO(struct dwc3_ep *dep, struct dwc3_trb *trb),
TP_ARGS(dep, trb),
TP_STRUCT__entry(
- __field(struct dwc3_ep *, dep)
+ __dynamic_array(char, name, DWC3_MSG_MAX)
__field(struct dwc3_trb *, trb)
+ __field(u32, bpl)
+ __field(u32, bph)
+ __field(u32, size)
+ __field(u32, ctrl)
),
TP_fast_assign(
- __entry->dep = dep;
+ snprintf(__get_str(name), DWC3_MSG_MAX, "%s", dep->name);
__entry->trb = trb;
+ __entry->bpl = trb->bpl;
+ __entry->bph = trb->bph;
+ __entry->size = trb->size;
+ __entry->ctrl = trb->ctrl;
),
TP_printk("%s: trb %p bph %08x bpl %08x size %08x ctrl %08x\n",
- __entry->dep->name, __entry->trb, __entry->trb->bph,
- __entry->trb->bpl, __entry->trb->size, __entry->trb->ctrl
+ __get_str(name), __entry->trb, __entry->bph, __entry->bpl,
+ __entry->size, __entry->ctrl
)
);
usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE;
usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
- usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT);
+ usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT | USB_BESL_SUPPORT);
/*
* The Superspeed USB Capability descriptor shall be implemented by all
dev_vdbg(&cdev->gadget->dev,
"reset acm control interface %d\n", intf);
usb_ep_disable(acm->notify);
- } else {
- dev_vdbg(&cdev->gadget->dev,
- "init acm ctrl interface %d\n", intf);
+ }
+
+ if (!acm->notify->desc)
if (config_ep_by_speed(cdev->gadget, f, acm->notify))
return -EINVAL;
- }
+
usb_ep_enable(acm->notify);
acm->notify->driver_data = acm;
return 0;
fail:
- usb_free_all_descriptors(f);
if (eem->port.out_ep)
eem->port.out_ep->driver_data = NULL;
if (eem->port.in_ep)
if (io_data->read && ret > 0) {
int i;
size_t pos = 0;
+
+ /*
+ * Since req->length may be bigger than io_data->len (after
+ * being rounded up to maxpacketsize), we may end up with more
+ * data then user space has space for.
+ */
+ ret = min_t(int, ret, io_data->len);
+
use_mm(io_data->mm);
for (i = 0; i < io_data->nr_segs; i++) {
+ size_t len = min_t(size_t, ret - pos,
+ io_data->iovec[i].iov_len);
+ if (!len)
+ break;
if (unlikely(copy_to_user(io_data->iovec[i].iov_base,
- &io_data->buf[pos],
- io_data->iovec[i].iov_len))) {
+ &io_data->buf[pos], len))) {
ret = -EFAULT;
break;
}
- pos += io_data->iovec[i].iov_len;
+ pos += len;
}
unuse_mm(io_data->mm);
}
struct ffs_epfile *epfile = file->private_data;
struct ffs_ep *ep;
char *data = NULL;
- ssize_t ret, data_len;
+ ssize_t ret, data_len = -EINVAL;
int halt;
/* Are we still active? */
/* Fire the request */
struct usb_request *req;
+ /*
+ * Sanity Check: even though data_len can't be used
+ * uninitialized at the time I write this comment, some
+ * compilers complain about this situation.
+ * In order to keep the code clean from warnings, data_len is
+ * being initialized to -EINVAL during its declaration, which
+ * means we can't rely on compiler anymore to warn no future
+ * changes won't result in data_len being used uninitialized.
+ * For such reason, we're adding this redundant sanity check
+ * here.
+ */
+ if (unlikely(data_len == -EINVAL)) {
+ WARN(1, "%s: data_len == -EINVAL\n", __func__);
+ ret = -EINVAL;
+ goto error_lock;
+ }
+
if (io_data->aio) {
req = usb_ep_alloc_request(ep->ep, GFP_KERNEL);
if (unlikely(!req))
goto error_lock;
req->buf = data;
- req->length = io_data->len;
+ req->length = data_len;
io_data->buf = data;
io_data->ep = ep->ep;
req = ep->req;
req->buf = data;
- req->length = io_data->len;
+ req->length = data_len;
req->context = &done;
req->complete = ffs_epfile_io_complete;
func->conf = c;
func->gadget = c->cdev->gadget;
- ffs_data_get(func->ffs);
-
/*
* in drivers/usb/gadget/configfs.c:configfs_composite_bind()
* configurations are bound in sequence with list_for_each_entry,
dev = MKDEV(major, hidg->minor);
status = cdev_add(&hidg->cdev, dev, 1);
if (status)
- goto fail;
+ goto fail_free_descs;
device_create(hidg_class, NULL, dev, NULL, "%s%d", "hidg", hidg->minor);
return 0;
+fail_free_descs:
+ usb_free_all_descriptors(f);
fail:
ERROR(f->config->cdev, "hidg_bind FAILED\n");
if (hidg->req != NULL) {
usb_ep_free_request(hidg->in_ep, hidg->req);
}
- usb_free_all_descriptors(f);
return status;
}
case 0: /* normal completion? */
if (ep == loop->out_ep) {
- /* loop this OUT packet back IN to the host */
req->zero = (req->actual < req->length);
req->length = req->actual;
- status = usb_ep_queue(loop->in_ep, req, GFP_ATOMIC);
- if (status == 0)
- return;
-
- /* "should never get here" */
- ERROR(cdev, "can't loop %s to %s: %d\n",
- ep->name, loop->in_ep->name,
- status);
}
/* queue the buffer for some later OUT packet */
req->length = buflen;
- status = usb_ep_queue(loop->out_ep, req, GFP_ATOMIC);
+ status = usb_ep_queue(ep, req, GFP_ATOMIC);
if (status == 0)
return;
return alloc_ep_req(ep, len, buflen);
}
-static int
-enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
+static int enable_endpoint(struct usb_composite_dev *cdev, struct f_loopback *loop,
+ struct usb_ep *ep)
{
- int result = 0;
- struct usb_ep *ep;
struct usb_request *req;
unsigned i;
+ int result;
- /* one endpoint writes data back IN to the host */
- ep = loop->in_ep;
+ /*
+ * one endpoint writes data back IN to the host while another endpoint
+ * just reads OUT packets
+ */
result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
if (result)
- return result;
+ goto fail0;
result = usb_ep_enable(ep);
if (result < 0)
- return result;
- ep->driver_data = loop;
-
- /* one endpoint just reads OUT packets */
- ep = loop->out_ep;
- result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
- if (result)
goto fail0;
-
- result = usb_ep_enable(ep);
- if (result < 0) {
-fail0:
- ep = loop->in_ep;
- usb_ep_disable(ep);
- ep->driver_data = NULL;
- return result;
- }
ep->driver_data = loop;
- /* allocate a bunch of read buffers and queue them all at once.
+ /*
+ * allocate a bunch of read buffers and queue them all at once.
* we buffer at most 'qlen' transfers; fewer if any need more
* than 'buflen' bytes each.
*/
for (i = 0; i < qlen && result == 0; i++) {
req = lb_alloc_ep_req(ep, 0);
- if (req) {
- req->complete = loopback_complete;
- result = usb_ep_queue(ep, req, GFP_ATOMIC);
- if (result)
- ERROR(cdev, "%s queue req --> %d\n",
- ep->name, result);
- } else {
- usb_ep_disable(ep);
- ep->driver_data = NULL;
- result = -ENOMEM;
- goto fail0;
+ if (!req)
+ goto fail1;
+
+ req->complete = loopback_complete;
+ result = usb_ep_queue(ep, req, GFP_ATOMIC);
+ if (result) {
+ ERROR(cdev, "%s queue req --> %d\n",
+ ep->name, result);
+ goto fail1;
}
}
+ return 0;
+
+fail1:
+ usb_ep_disable(ep);
+
+fail0:
+ return result;
+}
+
+static int
+enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
+{
+ int result = 0;
+
+ result = enable_endpoint(cdev, loop, loop->in_ep);
+ if (result)
+ return result;
+
+ result = enable_endpoint(cdev, loop, loop->out_ep);
+ if (result)
+ return result;
+
DBG(cdev, "%s enabled\n", loop->function.name);
return result;
}
return 0;
fail:
- usb_free_all_descriptors(f);
if (ncm->notify_req) {
kfree(ncm->notify_req->buf);
usb_ep_free_request(ncm->notify, ncm->notify_req);
struct gserial port;
u8 ctrl_id;
u8 data_id;
+ u8 cur_alt;
u8 port_num;
u8 can_activate;
};
} else
goto fail;
+ obex->cur_alt = alt;
+
return 0;
fail:
{
struct f_obex *obex = func_to_obex(f);
- if (intf == obex->ctrl_id)
- return 0;
-
- return obex->port.in->driver_data ? 1 : 0;
+ return obex->cur_alt;
}
static void obex_disable(struct usb_function *f)
return 0;
fail:
- usb_free_all_descriptors(f);
/* we might as well release our claims on endpoints */
if (obex->port.out)
obex->port.out->driver_data = NULL;
err_req:
for (i = 0; i < phonet_rxq_size && fp->out_reqv[i]; i++)
usb_ep_free_request(fp->out_ep, fp->out_reqv[i]);
-err:
usb_free_all_descriptors(f);
+err:
if (fp->out_ep)
fp->out_ep->driver_data = NULL;
if (fp->in_ep)
if (rndis->manufacturer && rndis->vendorID &&
rndis_set_param_vendor(rndis->config, rndis->vendorID,
- rndis->manufacturer))
- goto fail;
+ rndis->manufacturer)) {
+ status = -EINVAL;
+ goto fail_free_descs;
+ }
/* NOTE: all that is done without knowing or caring about
* the network link ... which is unavailable to this code
rndis->notify->name);
return 0;
+fail_free_descs:
+ usb_free_all_descriptors(f);
fail:
kfree(f->os_desc_table);
f->os_desc_n = 0;
- usb_free_all_descriptors(f);
if (rndis->notify_req) {
kfree(rndis->notify_req->buf);
return 0;
fail:
- usb_free_all_descriptors(f);
/* we might as well release our claims on endpoints */
if (geth->port.out_ep)
geth->port.out_ep->driver_data = NULL;
return 0;
}
+static void snd_uac2_release(struct device *dev)
+{
+ dev_dbg(dev, "releasing '%s'\n", dev_name(dev));
+}
+
static int alsa_uac2_init(struct audio_dev *agdev)
{
struct snd_uac2_chip *uac2 = &agdev->uac2;
uac2->pdev.id = 0;
uac2->pdev.name = uac2_name;
+ uac2->pdev.dev.release = snd_uac2_release;
/* Register snd_uac2 driver */
err = platform_driver_register(&uac2->pdrv);
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+ .wMaxPacketSize = cpu_to_le16(1023),
.bInterval = 1,
};
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+ .wMaxPacketSize = cpu_to_le16(1024),
.bInterval = 4,
};
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+ .wMaxPacketSize = cpu_to_le16(1023),
.bInterval = 1,
};
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+ .wMaxPacketSize = cpu_to_le16(1024),
.bInterval = 4,
};
struct snd_uac2_chip *uac2 = prm->uac2;
int i;
+ if (!prm->ep_enabled)
+ return;
+
prm->ep_enabled = false;
for (i = 0; i < USB_XFERS; i++) {
prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
if (!prm->rbuf) {
prm->max_psize = 0;
- goto err;
+ goto err_free_descs;
}
prm = &agdev->uac2.p_prm;
prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
if (!prm->rbuf) {
prm->max_psize = 0;
- goto err;
+ goto err_free_descs;
}
ret = alsa_uac2_init(agdev);
if (ret)
- goto err;
+ goto err_free_descs;
return 0;
+
+err_free_descs:
+ usb_free_all_descriptors(fn);
err:
kfree(agdev->uac2.p_prm.rbuf);
kfree(agdev->uac2.c_prm.rbuf);
- usb_free_all_descriptors(fn);
if (agdev->in_ep)
agdev->in_ep->driver_data = NULL;
if (agdev->out_ep)
else if (interface != uvc->streaming_intf)
return -EINVAL;
else
- return uvc->state == UVC_STATE_STREAMING ? 1 : 0;
+ return uvc->video.ep->driver_data ? 1 : 0;
}
static int
uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
{
struct uvc_device *uvc = to_uvc(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
struct v4l2_event v4l2_event;
struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
int ret;
- INFO(f->config->cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt);
+ INFO(cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt);
if (interface == uvc->control_intf) {
if (alt)
return -EINVAL;
+ if (uvc->control_ep->driver_data) {
+ INFO(cdev, "reset UVC Control\n");
+ usb_ep_disable(uvc->control_ep);
+ uvc->control_ep->driver_data = NULL;
+ }
+
+ if (!uvc->control_ep->desc)
+ if (config_ep_by_speed(cdev->gadget, f, uvc->control_ep))
+ return -EINVAL;
+
+ usb_ep_enable(uvc->control_ep);
+ uvc->control_ep->driver_data = uvc;
+
if (uvc->state == UVC_STATE_DISCONNECTED) {
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_CONNECT;
- uvc_event->speed = f->config->cdev->gadget->speed;
+ uvc_event->speed = cdev->gadget->speed;
v4l2_event_queue(uvc->vdev, &v4l2_event);
uvc->state = UVC_STATE_CONNECTED;
if (uvc->state != UVC_STATE_STREAMING)
return 0;
- if (uvc->video.ep)
+ if (uvc->video.ep) {
usb_ep_disable(uvc->video.ep);
+ uvc->video.ep->driver_data = NULL;
+ }
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_STREAMOFF;
if (uvc->state != UVC_STATE_CONNECTED)
return 0;
- if (uvc->video.ep) {
- ret = config_ep_by_speed(f->config->cdev->gadget,
- &(uvc->func), uvc->video.ep);
- if (ret)
- return ret;
- usb_ep_enable(uvc->video.ep);
+ if (!uvc->video.ep)
+ return -EINVAL;
+
+ if (uvc->video.ep->driver_data) {
+ INFO(cdev, "reset UVC\n");
+ usb_ep_disable(uvc->video.ep);
+ uvc->video.ep->driver_data = NULL;
}
+ ret = config_ep_by_speed(f->config->cdev->gadget,
+ &(uvc->func), uvc->video.ep);
+ if (ret)
+ return ret;
+ usb_ep_enable(uvc->video.ep);
+ uvc->video.ep->driver_data = uvc;
+
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_STREAMON;
v4l2_event_queue(uvc->vdev, &v4l2_event);
v4l2_event_queue(uvc->vdev, &v4l2_event);
uvc->state = UVC_STATE_DISCONNECTED;
+
+ if (uvc->video.ep->driver_data) {
+ usb_ep_disable(uvc->video.ep);
+ uvc->video.ep->driver_data = NULL;
+ }
+
+ if (uvc->control_ep->driver_data) {
+ usb_ep_disable(uvc->control_ep);
+ uvc->control_ep->driver_data = NULL;
+ }
}
/* --------------------------------------------------------------------------
if (!enable) {
for (i = 0; i < UVC_NUM_REQUESTS; ++i)
- usb_ep_dequeue(video->ep, video->req[i]);
+ if (video->req[i])
+ usb_ep_dequeue(video->ep, video->req[i]);
uvc_video_free_requests(video);
uvcg_queue_enable(&video->queue, 0);
config USB_GADGET_XILINX
tristate "Xilinx USB Driver"
+ depends on HAS_DMA
depends on OF || COMPILE_TEST
help
USB peripheral controller driver for Xilinx USB2 device.
{
struct usb_udc *udc = container_of(dev, struct usb_udc, dev);
+ if (!udc->driver) {
+ dev_err(dev, "soft-connect without a gadget driver\n");
+ return -EOPNOTSUPP;
+ }
+
if (sysfs_streq(buf, "connect")) {
usb_gadget_udc_start(udc->gadget, udc->driver);
usb_gadget_connect(udc->gadget);
}
}
- if (!list_empty(&controller->early_tx_list)) {
+ if (!list_empty(&controller->early_tx_list) &&
+ !hrtimer_is_queued(&controller->early_tx)) {
ret = HRTIMER_RESTART;
hrtimer_forward_now(&controller->early_tx,
ktime_set(0, 20 * NSEC_PER_USEC));
struct dsps_glue *glue = dev_get_drvdata(dev);
const struct dsps_musb_wrapper *wrp = glue->wrp;
struct musb *musb = platform_get_drvdata(glue->musb);
- void __iomem *mbase = musb->ctrl_base;
+ void __iomem *mbase;
del_timer_sync(&glue->timer);
+
+ if (!musb)
+ /* This can happen if the musb device is in -EPROBE_DEFER */
+ return 0;
+
+ mbase = musb->ctrl_base;
glue->context.control = dsps_readl(mbase, wrp->control);
glue->context.epintr = dsps_readl(mbase, wrp->epintr_set);
glue->context.coreintr = dsps_readl(mbase, wrp->coreintr_set);
struct dsps_glue *glue = dev_get_drvdata(dev);
const struct dsps_musb_wrapper *wrp = glue->wrp;
struct musb *musb = platform_get_drvdata(glue->musb);
- void __iomem *mbase = musb->ctrl_base;
+ void __iomem *mbase;
+
+ if (!musb)
+ return 0;
+ mbase = musb->ctrl_base;
dsps_writel(mbase, wrp->control, glue->context.control);
dsps_writel(mbase, wrp->epintr_set, glue->context.epintr);
dsps_writel(mbase, wrp->coreintr_set, glue->context.coreintr);
dsps_writel(mbase, wrp->mode, glue->context.mode);
dsps_writel(mbase, wrp->tx_mode, glue->context.tx_mode);
dsps_writel(mbase, wrp->rx_mode, glue->context.rx_mode);
- setup_timer(&glue->timer, otg_timer, (unsigned long) musb);
+ if (musb->xceiv->state == OTG_STATE_B_IDLE &&
+ musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE)
+ mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);
return 0;
}
{ USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
{ USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */
{ USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */
+ { USB_DEVICE(0x1BA4, 0x0002) }, /* Silicon Labs 358x factory default */
{ USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */
{ USB_DEVICE(0x1D6F, 0x0010) }, /* Seluxit ApS RF Dongle */
{ USB_DEVICE(0x1E29, 0x0102) }, /* Festo CPX-USB */
* /sys/bus/usb-serial/drivers/ftdi_sio/new_id and send a patch or report.
*/
static const struct usb_device_id id_table_combined[] = {
+ { USB_DEVICE(FTDI_VID, FTDI_BRICK_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CTI_MINI_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CTI_NANO_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_5_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_6_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_7_PID) },
+ { USB_DEVICE(XSENS_VID, XSENS_AWINDA_DONGLE_PID) },
+ { USB_DEVICE(XSENS_VID, XSENS_AWINDA_STATION_PID) },
{ USB_DEVICE(XSENS_VID, XSENS_CONVERTER_PID) },
{ USB_DEVICE(XSENS_VID, XSENS_MTW_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_OMNI1509) },
/*** third-party PIDs (using FTDI_VID) ***/
+/*
+ * Certain versions of the official Windows FTDI driver reprogrammed
+ * counterfeit FTDI devices to PID 0. Support these devices anyway.
+ */
+#define FTDI_BRICK_PID 0x0000
+
#define FTDI_LUMEL_PD12_PID 0x6002
/*
* Xsens Technologies BV products (http://www.xsens.com).
*/
#define XSENS_VID 0x2639
-#define XSENS_CONVERTER_PID 0xD00D /* Xsens USB-serial converter */
+#define XSENS_AWINDA_STATION_PID 0x0101
+#define XSENS_AWINDA_DONGLE_PID 0x0102
#define XSENS_MTW_PID 0x0200 /* Xsens MTw */
+#define XSENS_CONVERTER_PID 0xD00D /* Xsens USB-serial converter */
+
+/* Xsens devices using FTDI VID */
#define XSENS_CONVERTER_0_PID 0xD388 /* Xsens USB converter */
#define XSENS_CONVERTER_1_PID 0xD389 /* Xsens Wireless Receiver */
#define XSENS_CONVERTER_2_PID 0xD38A
int result;
int dtr = 0;
int rts = 0;
- unsigned char *transfer_buffer;
- int transfer_buffer_length = 8;
/* FIXME: locking ? */
priv = usb_get_serial_port_data(port);
return -EINVAL;
}
- /* allocate memory for transfer buffer */
- transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
- if (!transfer_buffer)
- return -ENOMEM;
-
if (set & TIOCM_RTS)
rts = 1;
if (set & TIOCM_DTR)
KOBIL_TIMEOUT);
}
dev_dbg(dev, "%s - Send set_status_line URB returns: %i\n", __func__, result);
- kfree(transfer_buffer);
return (result < 0) ? result : 0;
}
{
struct usb_serial_port *port = tty->driver_data;
struct kobil_private *priv = usb_get_serial_port_data(port);
- unsigned char *transfer_buffer;
- int transfer_buffer_length = 8;
int result;
if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID ||
switch (cmd) {
case TCFLSH:
- transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL);
- if (!transfer_buffer)
- return -ENOBUFS;
-
result = usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
SUSBCRequest_Misc,
dev_dbg(&port->dev,
"%s - Send reset_all_queues (FLUSH) URB returns: %i\n",
__func__, result);
- kfree(transfer_buffer);
return (result < 0) ? -EIO: 0;
default:
return -ENOIOCTLCMD;
#define TELIT_PRODUCT_DE910_DUAL 0x1010
#define TELIT_PRODUCT_UE910_V2 0x1012
#define TELIT_PRODUCT_LE920 0x1200
+#define TELIT_PRODUCT_LE910 0x1201
/* ZTE PRODUCTS */
#define ZTE_VENDOR_ID 0x19d2
/* Haier products */
#define HAIER_VENDOR_ID 0x201e
+#define HAIER_PRODUCT_CE81B 0x10f8
#define HAIER_PRODUCT_CE100 0x2009
/* Cinterion (formerly Siemens) products */
.reserved = BIT(3) | BIT(4),
};
+static const struct option_blacklist_info telit_le910_blacklist = {
+ .sendsetup = BIT(0),
+ .reserved = BIT(1) | BIT(2),
+};
+
static const struct option_blacklist_info telit_le920_blacklist = {
.sendsetup = BIT(0),
.reserved = BIT(1) | BIT(5),
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UE910_V2) },
+ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910),
+ .driver_info = (kernel_ulong_t)&telit_le910_blacklist },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920),
.driver_info = (kernel_ulong_t)&telit_le920_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */
{ USB_DEVICE(LONGCHEER_VENDOR_ID, ZOOM_PRODUCT_4597) },
{ USB_DEVICE(LONGCHEER_VENDOR_ID, IBALL_3_5G_CONNECT) },
{ USB_DEVICE(HAIER_VENDOR_ID, HAIER_PRODUCT_CE100) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HAIER_VENDOR_ID, HAIER_PRODUCT_CE81B, 0xff, 0xff, 0xff) },
/* Pirelli */
{ USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_C100_1, 0xff) },
{ USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_C100_2, 0xff) },
return 1;
while ((options = strsep(&this_opt, ",")) != NULL) {
- if (!strncmp(options, "font:", 5))
+ if (!strncmp(options, "font:", 5)) {
strlcpy(fontname, options + 5, sizeof(fontname));
+ continue;
+ }
if (!strncmp(options, "scrollback:", 11)) {
options += 11;
fbcon_softback_size = simple_strtoul(options, &options, 0);
if (*options == 'k' || *options == 'K') {
fbcon_softback_size *= 1024;
- options++;
}
- if (*options != ',')
- return 1;
- options++;
- } else
- return 1;
+ }
+ continue;
}
if (!strncmp(options, "map:", 4)) {
fbcon_map_override();
}
-
- return 1;
+ continue;
}
if (!strncmp(options, "vc:", 3)) {
if (*options++ == '-')
last_fb_vc = simple_strtoul(options, &options, 10) - 1;
fbcon_is_default = 0;
- }
+ continue;
+ }
if (!strncmp(options, "rotate:", 7)) {
options += 7;
initial_rotation = simple_strtoul(options, &options, 0);
if (initial_rotation > 3)
initial_rotation = 0;
+ continue;
}
}
return 1;
static int cursor_size_lastto;
static u32 vgacon_xres;
static u32 vgacon_yres;
-static struct vgastate state;
+static struct vgastate vgastate;
#define BLANK 0x0020
vga_video_num_lines = screen_info.orig_video_lines;
vga_video_num_columns = screen_info.orig_video_cols;
- state.vgabase = NULL;
+ vgastate.vgabase = NULL;
if (screen_info.orig_video_mode == 7) {
/* Monochrome display */
{
int i, j;
- vga_w(state.vgabase, VGA_PEL_MSK, 0xff);
+ vga_w(vgastate.vgabase, VGA_PEL_MSK, 0xff);
for (i = j = 0; i < 16; i++) {
- vga_w(state.vgabase, VGA_PEL_IW, table[i]);
- vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
- vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
- vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
+ vga_w(vgastate.vgabase, VGA_PEL_IW, table[i]);
+ vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
+ vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
+ vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
}
}
switch (blank) {
case 0: /* Unblank */
if (vga_vesa_blanked) {
- vga_vesa_unblank(&state);
+ vga_vesa_unblank(&vgastate);
vga_vesa_blanked = 0;
}
if (vga_palette_blanked) {
case 1: /* Normal blanking */
case -1: /* Obsolete */
if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) {
- vga_pal_blank(&state);
+ vga_pal_blank(&vgastate);
vga_palette_blanked = 1;
return 0;
}
return 1;
default: /* VESA blanking */
if (vga_video_type == VIDEO_TYPE_VGAC) {
- vga_vesa_blank(&state, blank - 1);
+ vga_vesa_blank(&vgastate, blank - 1);
vga_vesa_blanked = blank;
}
return 0;
(charcount != 256 && charcount != 512))
return -EINVAL;
- rc = vgacon_do_font_op(&state, font->data, 1, charcount == 512);
+ rc = vgacon_do_font_op(&vgastate, font->data, 1, charcount == 512);
if (rc)
return rc;
font->charcount = vga_512_chars ? 512 : 256;
if (!font->data)
return 0;
- return vgacon_do_font_op(&state, font->data, 0, vga_512_chars);
+ return vgacon_do_font_op(&vgastate, font->data, 0, vga_512_chars);
}
#else
#include <linux/regulator/consumer.h>
#include <video/videomode.h>
-#include <mach/cpu.h>
#include <asm/gpio.h>
#include <video/atmel_lcdc.h>
{},
};
+MODULE_DEVICE_TABLE(of, tvc_of_match);
+
static struct platform_driver tvc_connector_driver = {
.probe = tvc_probe,
.remove = __exit_p(tvc_remove),
.name = "connector-analog-tv",
.owner = THIS_MODULE,
.of_match_table = tvc_of_match,
+ .suppress_bind_attrs = true,
},
};
.name = "connector-dvi",
.owner = THIS_MODULE,
.of_match_table = dvic_of_match,
+ .suppress_bind_attrs = true,
},
};
.name = "connector-hdmi",
.owner = THIS_MODULE,
.of_match_table = hdmic_of_match,
+ .suppress_bind_attrs = true,
},
};
.name = "tfp410",
.owner = THIS_MODULE,
.of_match_table = tfp410_of_match,
+ .suppress_bind_attrs = true,
},
};
.name = "tpd12s015",
.owner = THIS_MODULE,
.of_match_table = tpd_of_match,
+ .suppress_bind_attrs = true,
},
};
.name = "panel-dpi",
.owner = THIS_MODULE,
.of_match_table = panel_dpi_of_match,
+ .suppress_bind_attrs = true,
},
};
.name = "panel-dsi-cm",
.owner = THIS_MODULE,
.of_match_table = dsicm_of_match,
+ .suppress_bind_attrs = true,
},
};
.name = "panel_lgphilips_lb035q02",
.owner = THIS_MODULE,
.of_match_table = lb035q02_of_match,
+ .suppress_bind_attrs = true,
},
};
.owner = THIS_MODULE,
.pm = NEC_8048_PM_OPS,
.of_match_table = nec_8048_of_match,
+ .suppress_bind_attrs = true,
},
.probe = nec_8048_probe,
.remove = nec_8048_remove,
.name = "panel-sharp-ls037v7dw01",
.owner = THIS_MODULE,
.of_match_table = sharp_ls_of_match,
+ .suppress_bind_attrs = true,
},
};
.name = "acx565akm",
.owner = THIS_MODULE,
.of_match_table = acx565akm_of_match,
+ .suppress_bind_attrs = true,
},
.probe = acx565akm_probe,
.remove = acx565akm_remove,
.name = "panel-tpo-td028ttec1",
.owner = THIS_MODULE,
.of_match_table = td028ttec1_of_match,
+ .suppress_bind_attrs = true,
},
};
.owner = THIS_MODULE,
.pm = &tpo_td043_spi_pm,
.of_match_table = tpo_td043_of_match,
+ .suppress_bind_attrs = true,
},
.probe = tpo_td043_probe,
.remove = tpo_td043_remove,
if (!mp->enabled)
goto out;
+ wait_pending_extra_info_updates();
+
if (!mgr_manual_update(mgr))
dispc_mgr_disable_sync(mgr->id);
DUMPREG(i, DISPC_OVL_FIFO_SIZE_STATUS);
DUMPREG(i, DISPC_OVL_ROW_INC);
DUMPREG(i, DISPC_OVL_PIXEL_INC);
+
if (dss_has_feature(FEAT_PRELOAD))
DUMPREG(i, DISPC_OVL_PRELOAD);
+ if (dss_has_feature(FEAT_MFLAG))
+ DUMPREG(i, DISPC_OVL_MFLAG_THRESHOLD);
if (i == OMAP_DSS_GFX) {
DUMPREG(i, DISPC_OVL_WINDOW_SKIP);
}
if (dss_has_feature(FEAT_ATTR2))
DUMPREG(i, DISPC_OVL_ATTRIBUTES2);
- if (dss_has_feature(FEAT_PRELOAD))
- DUMPREG(i, DISPC_OVL_PRELOAD);
- if (dss_has_feature(FEAT_MFLAG))
- DUMPREG(i, DISPC_OVL_MFLAG_THRESHOLD);
}
#undef DISPC_REG
.owner = THIS_MODULE,
.pm = &dispc_pm_ops,
.of_match_table = dispc_of_match,
+ .suppress_bind_attrs = true,
},
};
DISPC_FIR_COEF_V2_OFFSET(n, i))
#define DISPC_OVL_PRELOAD(n) (DISPC_OVL_BASE(n) + \
DISPC_PRELOAD_OFFSET(n))
-#define DISPC_OVL_MFLAG_THRESHOLD(n) (DISPC_OVL_BASE(n) + \
- DISPC_MFLAG_THRESHOLD_OFFSET(n))
+#define DISPC_OVL_MFLAG_THRESHOLD(n) DISPC_MFLAG_THRESHOLD_OFFSET(n)
/* DISPC up/downsampling FIR filter coefficient structure */
struct dispc_coef {
.driver = {
.name = "omapdss_dpi",
.owner = THIS_MODULE,
+ .suppress_bind_attrs = true,
},
};
} else if (dss_has_feature(FEAT_DSI_PLL_SELFREQDCO)) {
f = cinfo->clkin4ddr < 1000000000 ? 0x2 : 0x4;
- l = FLD_MOD(l, f, 4, 1); /* PLL_SELFREQDCO */
+ l = FLD_MOD(l, f, 3, 1); /* PLL_SELFREQDCO */
}
l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
.owner = THIS_MODULE,
.pm = &dsi_pm_ops,
.of_match_table = dsi_of_match,
+ .suppress_bind_attrs = true,
},
};
.owner = THIS_MODULE,
.pm = &dss_pm_ops,
.of_match_table = dss_of_match,
+ .suppress_bind_attrs = true,
},
};
.owner = THIS_MODULE,
.pm = &hdmi_pm_ops,
.of_match_table = hdmi_of_match,
+ .suppress_bind_attrs = true,
},
};
.owner = THIS_MODULE,
.pm = &hdmi_pm_ops,
.of_match_table = hdmi_of_match,
+ .suppress_bind_attrs = true,
},
};
r = FLD_MOD(r, 0x0, 14, 14); /* PHY_CLKINEN de-assert during locking */
r = FLD_MOD(r, fmt->refsel, 22, 21); /* REFSEL */
- if (fmt->dcofreq) {
- /* divider programming for frequency beyond 1000Mhz */
- REG_FLD_MOD(pll->base, PLLCTRL_CFG3, fmt->regsd, 17, 10);
+ if (fmt->dcofreq)
r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */
- } else {
+ else
r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */
- }
hdmi_write_reg(pll->base, PLLCTRL_CFG2, r);
+ REG_FLD_MOD(pll->base, PLLCTRL_CFG3, fmt->regsd, 17, 10);
+
r = hdmi_read_reg(pll->base, PLLCTRL_CFG4);
r = FLD_MOD(r, fmt->regm2, 24, 18);
r = FLD_MOD(r, fmt->regmf, 17, 0);
/* wait for bit change */
if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_GO,
- 0, 0, 1) != 1) {
- DSSERR("PLL GO bit not set\n");
+ 0, 0, 0) != 0) {
+ DSSERR("PLL GO bit not clearing\n");
return -ETIMEDOUT;
}
.name = "omapdss_rfbi",
.owner = THIS_MODULE,
.pm = &rfbi_pm_ops,
+ .suppress_bind_attrs = true,
},
};
.driver = {
.name = "omapdss_sdi",
.owner = THIS_MODULE,
+ .suppress_bind_attrs = true,
},
};
.owner = THIS_MODULE,
.pm = &venc_pm_ops,
.of_match_table = venc_of_match,
+ .suppress_bind_attrs = true,
},
};
if (fbdev == NULL)
return;
- for (i = 0; i < fbdev->num_fbs; i++) {
- struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
- int j;
+ for (i = 0; i < fbdev->num_overlays; i++) {
+ struct omap_overlay *ovl = fbdev->overlays[i];
- for (j = 0; j < ofbi->num_overlays; j++) {
- struct omap_overlay *ovl = ofbi->overlays[j];
- ovl->disable(ovl);
- }
+ ovl->disable(ovl);
+
+ if (ovl->manager)
+ ovl->unset_manager(ovl);
}
for (i = 0; i < fbdev->num_fbs; i++)
return r;
}
-static int __exit omapfb_remove(struct platform_device *pdev)
+static int omapfb_remove(struct platform_device *pdev)
{
struct omapfb2_device *fbdev = platform_get_drvdata(pdev);
static struct platform_driver omapfb_driver = {
.probe = omapfb_probe,
- .remove = __exit_p(omapfb_remove),
+ .remove = omapfb_remove,
.driver = {
.name = "omapfb",
.owner = THIS_MODULE,
module_platform_driver(omapfb_driver);
+MODULE_ALIAS("platform:omapfb");
MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
MODULE_DESCRIPTION("OMAP2/3 Framebuffer");
MODULE_LICENSE("GPL v2");
static int omap_hdq_probe(struct platform_device *pdev);
static int omap_hdq_remove(struct platform_device *pdev);
+static struct of_device_id omap_hdq_dt_ids[] = {
+ { .compatible = "ti,omap3-1w" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, omap_hdq_dt_ids);
+
static struct platform_driver omap_hdq_driver = {
.probe = omap_hdq_probe,
.remove = omap_hdq_remove,
.driver = {
.name = "omap_hdq",
+ .of_match_table = omap_hdq_dt_ids,
},
};
}
EXPORT_SYMBOL_GPL(blkdev_write_iter);
-static ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to)
+ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to)
{
struct file *file = iocb->ki_filp;
struct inode *bd_inode = file->f_mapping->host;
iov_iter_truncate(to, size);
return generic_file_read_iter(iocb, to);
}
+EXPORT_SYMBOL_GPL(blkdev_read_iter);
/*
* Try to release a page associated with block device when the system
struct btrfs_root *root, unsigned long count);
int btrfs_async_run_delayed_refs(struct btrfs_root *root,
unsigned long count, int wait);
-int btrfs_lookup_extent(struct btrfs_root *root, u64 start, u64 len);
+int btrfs_lookup_data_extent(struct btrfs_root *root, u64 start, u64 len);
int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytenr,
u64 offset, int metadata, u64 *refs, u64 *flags);
struct btrfs_super_block *sb = fs_info->super_copy;
int ret = 0;
- if (sb->root_level > BTRFS_MAX_LEVEL) {
- printk(KERN_ERR "BTRFS: tree_root level too big: %d > %d\n",
- sb->root_level, BTRFS_MAX_LEVEL);
+ if (btrfs_super_root_level(sb) >= BTRFS_MAX_LEVEL) {
+ printk(KERN_ERR "BTRFS: tree_root level too big: %d >= %d\n",
+ btrfs_super_root_level(sb), BTRFS_MAX_LEVEL);
ret = -EINVAL;
}
- if (sb->chunk_root_level > BTRFS_MAX_LEVEL) {
- printk(KERN_ERR "BTRFS: chunk_root level too big: %d > %d\n",
- sb->chunk_root_level, BTRFS_MAX_LEVEL);
+ if (btrfs_super_chunk_root_level(sb) >= BTRFS_MAX_LEVEL) {
+ printk(KERN_ERR "BTRFS: chunk_root level too big: %d >= %d\n",
+ btrfs_super_chunk_root_level(sb), BTRFS_MAX_LEVEL);
ret = -EINVAL;
}
- if (sb->log_root_level > BTRFS_MAX_LEVEL) {
- printk(KERN_ERR "BTRFS: log_root level too big: %d > %d\n",
- sb->log_root_level, BTRFS_MAX_LEVEL);
+ if (btrfs_super_log_root_level(sb) >= BTRFS_MAX_LEVEL) {
+ printk(KERN_ERR "BTRFS: log_root level too big: %d >= %d\n",
+ btrfs_super_log_root_level(sb), BTRFS_MAX_LEVEL);
ret = -EINVAL;
}
* The common minimum, we don't know if we can trust the nodesize/sectorsize
* items yet, they'll be verified later. Issue just a warning.
*/
- if (!IS_ALIGNED(sb->root, 4096))
+ if (!IS_ALIGNED(btrfs_super_root(sb), 4096))
printk(KERN_WARNING "BTRFS: tree_root block unaligned: %llu\n",
sb->root);
- if (!IS_ALIGNED(sb->chunk_root, 4096))
+ if (!IS_ALIGNED(btrfs_super_chunk_root(sb), 4096))
printk(KERN_WARNING "BTRFS: tree_root block unaligned: %llu\n",
sb->chunk_root);
- if (!IS_ALIGNED(sb->log_root, 4096))
+ if (!IS_ALIGNED(btrfs_super_log_root(sb), 4096))
printk(KERN_WARNING "BTRFS: tree_root block unaligned: %llu\n",
- sb->log_root);
+ btrfs_super_log_root(sb));
if (memcmp(fs_info->fsid, sb->dev_item.fsid, BTRFS_UUID_SIZE) != 0) {
printk(KERN_ERR "BTRFS: dev_item UUID does not match fsid: %pU != %pU\n",
* Hint to catch really bogus numbers, bitflips or so, more exact checks are
* done later
*/
- if (sb->num_devices > (1UL << 31))
+ if (btrfs_super_num_devices(sb) > (1UL << 31))
printk(KERN_WARNING "BTRFS: suspicious number of devices: %llu\n",
- sb->num_devices);
+ btrfs_super_num_devices(sb));
- if (sb->bytenr != BTRFS_SUPER_INFO_OFFSET) {
+ if (btrfs_super_bytenr(sb) != BTRFS_SUPER_INFO_OFFSET) {
printk(KERN_ERR "BTRFS: super offset mismatch %llu != %u\n",
- sb->bytenr, BTRFS_SUPER_INFO_OFFSET);
+ btrfs_super_bytenr(sb), BTRFS_SUPER_INFO_OFFSET);
ret = -EINVAL;
}
* The generation is a global counter, we'll trust it more than the others
* but it's still possible that it's the one that's wrong.
*/
- if (sb->generation < sb->chunk_root_generation)
+ if (btrfs_super_generation(sb) < btrfs_super_chunk_root_generation(sb))
printk(KERN_WARNING
"BTRFS: suspicious: generation < chunk_root_generation: %llu < %llu\n",
- sb->generation, sb->chunk_root_generation);
- if (sb->generation < sb->cache_generation && sb->cache_generation != (u64)-1)
+ btrfs_super_generation(sb), btrfs_super_chunk_root_generation(sb));
+ if (btrfs_super_generation(sb) < btrfs_super_cache_generation(sb)
+ && btrfs_super_cache_generation(sb) != (u64)-1)
printk(KERN_WARNING
"BTRFS: suspicious: generation < cache_generation: %llu < %llu\n",
- sb->generation, sb->cache_generation);
+ btrfs_super_generation(sb), btrfs_super_cache_generation(sb));
return ret;
}
rcu_read_unlock();
}
-/* simple helper to search for an existing extent at a given offset */
-int btrfs_lookup_extent(struct btrfs_root *root, u64 start, u64 len)
+/* simple helper to search for an existing data extent at a given offset */
+int btrfs_lookup_data_extent(struct btrfs_root *root, u64 start, u64 len)
{
int ret;
struct btrfs_key key;
key.type = BTRFS_EXTENT_ITEM_KEY;
ret = btrfs_search_slot(NULL, root->fs_info->extent_root, &key, path,
0, 0);
- if (ret > 0) {
- btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
- if (key.objectid == start &&
- key.type == BTRFS_METADATA_ITEM_KEY)
- ret = 0;
- }
btrfs_free_path(path);
return ret;
}
else
key.type = BTRFS_EXTENT_ITEM_KEY;
-again:
ret = btrfs_search_slot(trans, root->fs_info->extent_root,
&key, path, 0, 0);
if (ret < 0)
key.offset == root->nodesize)
ret = 0;
}
- if (ret) {
- key.objectid = bytenr;
- key.type = BTRFS_EXTENT_ITEM_KEY;
- key.offset = root->nodesize;
- btrfs_release_path(path);
- goto again;
- }
}
if (ret == 0) {
extent_map_exit();
extent_io_exit();
btrfs_interface_exit();
+ btrfs_end_io_wq_exit();
unregister_filesystem(&btrfs_fs_type);
btrfs_exit_sysfs();
btrfs_cleanup_fs_uuids();
* is this extent already allocated in the extent
* allocation tree? If so, just add a reference
*/
- ret = btrfs_lookup_extent(root, ins.objectid,
+ ret = btrfs_lookup_data_extent(root, ins.objectid,
ins.offset);
if (ret == 0) {
ret = btrfs_inc_extent_ref(trans, root,
page_cache_release(page);
}
-
-static int quiet_error(struct buffer_head *bh)
-{
- if (!test_bit(BH_Quiet, &bh->b_state) && printk_ratelimit())
- return 0;
- return 1;
-}
-
-
-static void buffer_io_error(struct buffer_head *bh)
+static void buffer_io_error(struct buffer_head *bh, char *msg)
{
char b[BDEVNAME_SIZE];
- printk(KERN_ERR "Buffer I/O error on device %s, logical block %Lu\n",
+
+ if (!test_bit(BH_Quiet, &bh->b_state))
+ printk_ratelimited(KERN_ERR
+ "Buffer I/O error on dev %s, logical block %llu%s\n",
bdevname(bh->b_bdev, b),
- (unsigned long long)bh->b_blocknr);
+ (unsigned long long)bh->b_blocknr, msg);
}
/*
void end_buffer_write_sync(struct buffer_head *bh, int uptodate)
{
- char b[BDEVNAME_SIZE];
-
if (uptodate) {
set_buffer_uptodate(bh);
} else {
- if (!quiet_error(bh)) {
- buffer_io_error(bh);
- printk(KERN_WARNING "lost page write due to "
- "I/O error on %s\n",
- bdevname(bh->b_bdev, b));
- }
+ buffer_io_error(bh, ", lost sync page write");
set_buffer_write_io_error(bh);
clear_buffer_uptodate(bh);
}
set_buffer_uptodate(bh);
} else {
clear_buffer_uptodate(bh);
- if (!quiet_error(bh))
- buffer_io_error(bh);
+ buffer_io_error(bh, ", async page read");
SetPageError(page);
}
*/
void end_buffer_async_write(struct buffer_head *bh, int uptodate)
{
- char b[BDEVNAME_SIZE];
unsigned long flags;
struct buffer_head *first;
struct buffer_head *tmp;
if (uptodate) {
set_buffer_uptodate(bh);
} else {
- if (!quiet_error(bh)) {
- buffer_io_error(bh);
- printk(KERN_WARNING "lost page write due to "
- "I/O error on %s\n",
- bdevname(bh->b_bdev, b));
- }
+ buffer_io_error(bh, ", lost async page write");
set_bit(AS_EIO, &page->mapping->flags);
set_buffer_write_io_error(bh);
clear_buffer_uptodate(bh);
"not specified.");
return 0;
}
- } else {
- if (sbi->s_jquota_fmt) {
- ext3_msg(sb, KERN_ERR, "error: journaled quota format "
- "specified with no journaling "
- "enabled.");
- return 0;
- }
}
#endif
return 1;
}
}
- allocated = ext4_split_extent(handle, inode, ppath,
- &split_map, split_flag, flags);
- if (allocated < 0)
- err = allocated;
-
+ err = ext4_split_extent(handle, inode, ppath, &split_map, split_flag,
+ flags);
+ if (err > 0)
+ err = 0;
out:
/* If we have gotten a failure, don't zero out status tree */
if (!err)
iov_iter_truncate(from, sbi->s_bitmap_maxbytes - pos);
}
+ iocb->private = &overwrite;
if (o_direct) {
blk_start_plug(&plug);
- iocb->private = &overwrite;
/* check whether we do a DIO overwrite or not */
if (ext4_should_dioread_nolock(inode) && !aio_mutex &&
struct buffer_head *block_bitmap_bh;
block_bitmap_bh = ext4_read_block_bitmap(sb, group);
+ if (!block_bitmap_bh) {
+ err = -EIO;
+ goto out;
+ }
BUFFER_TRACE(block_bitmap_bh, "get block bitmap access");
err = ext4_journal_get_write_access(handle, block_bitmap_bh);
if (err) {
if (val)
ext4_set_inode_flag(inode, EXT4_INODE_JOURNAL_DATA);
else {
- jbd2_journal_flush(journal);
+ err = jbd2_journal_flush(journal);
+ if (err < 0) {
+ jbd2_journal_unlock_updates(journal);
+ ext4_inode_resume_unlocked_dio(inode);
+ return err;
+ }
ext4_clear_inode_flag(inode, EXT4_INODE_JOURNAL_DATA);
}
ext4_set_aops(inode);
hinfo.hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned;
hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed;
ext4fs_dirhash(name, namelen, &hinfo);
+ memset(frames, 0, sizeof(frames));
frame = frames;
frame->entries = entries;
frame->at = entries;
frame->bh = bh;
bh = bh2;
- ext4_handle_dirty_dx_node(handle, dir, frame->bh);
- ext4_handle_dirty_dirent_node(handle, dir, bh);
+ retval = ext4_handle_dirty_dx_node(handle, dir, frame->bh);
+ if (retval)
+ goto out_frames;
+ retval = ext4_handle_dirty_dirent_node(handle, dir, bh);
+ if (retval)
+ goto out_frames;
de = do_split(handle,dir, &bh, frame, &hinfo);
if (IS_ERR(de)) {
- /*
- * Even if the block split failed, we have to properly write
- * out all the changes we did so far. Otherwise we can end up
- * with corrupted filesystem.
- */
- ext4_mark_inode_dirty(handle, dir);
- dx_release(frames);
- return PTR_ERR(de);
+ retval = PTR_ERR(de);
+ goto out_frames;
}
dx_release(frames);
retval = add_dirent_to_buf(handle, dentry, inode, de, bh);
brelse(bh);
return retval;
+out_frames:
+ /*
+ * Even if the block split failed, we have to properly write
+ * out all the changes we did so far. Otherwise we can end up
+ * with corrupted filesystem.
+ */
+ ext4_mark_inode_dirty(handle, dir);
+ dx_release(frames);
+ return retval;
}
/*
break;
if (meta_bg == 0)
- backup_block = group * bpg + blk_off;
+ backup_block = ((ext4_fsblk_t)group) * bpg + blk_off;
else
backup_block = (ext4_group_first_block_no(sb, group) +
ext4_bg_has_super(sb, group));
#ifdef CONFIG_EXT4_FS_POSIX_ACL
set_opt(sb, POSIX_ACL);
#endif
+ /* don't forget to enable journal_csum when metadata_csum is enabled. */
+ if (ext4_has_metadata_csum(sb))
+ set_opt(sb, JOURNAL_CHECKSUM);
+
if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_DATA)
set_opt(sb, JOURNAL_DATA);
else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_ORDERED)
if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_MMP) &&
!(sb->s_flags & MS_RDONLY))
if (ext4_multi_mount_protect(sb, le64_to_cpu(es->s_mmp_block)))
- goto failed_mount3;
+ goto failed_mount3a;
/*
* The first inode we look at is the journal inode. Don't try
if (!test_opt(sb, NOLOAD) &&
EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL)) {
if (ext4_load_journal(sb, es, journal_devnum))
- goto failed_mount3;
+ goto failed_mount3a;
} else if (test_opt(sb, NOLOAD) && !(sb->s_flags & MS_RDONLY) &&
EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER)) {
ext4_msg(sb, KERN_ERR, "required journal recovery "
jbd2_journal_destroy(sbi->s_journal);
sbi->s_journal = NULL;
}
+failed_mount3a:
ext4_es_unregister_shrinker(sbi);
failed_mount3:
del_timer_sync(&sbi->s_err_report);
goto restore_opts;
}
+ if ((old_opts.s_mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) ^
+ test_opt(sb, JOURNAL_CHECKSUM)) {
+ ext4_msg(sb, KERN_ERR, "changing journal_checksum "
+ "during remount not supported");
+ err = -EINVAL;
+ goto restore_opts;
+ }
+
if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) {
if (test_opt2(sb, EXPLICIT_DELALLOC)) {
ext4_msg(sb, KERN_ERR, "can't mount with "
#define BEQUIET
static int isofs_hashi(const struct dentry *parent, struct qstr *qstr);
-static int isofs_hash(const struct dentry *parent, struct qstr *qstr);
static int isofs_dentry_cmpi(const struct dentry *parent,
const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name);
-static int isofs_dentry_cmp(const struct dentry *parent,
- const struct dentry *dentry,
- unsigned int len, const char *str, const struct qstr *name);
#ifdef CONFIG_JOLIET
static int isofs_hashi_ms(const struct dentry *parent, struct qstr *qstr);
static const struct dentry_operations isofs_dentry_ops[] = {
- {
- .d_hash = isofs_hash,
- .d_compare = isofs_dentry_cmp,
- },
{
.d_hash = isofs_hashi,
.d_compare = isofs_dentry_cmpi,
return 1;
}
-static int
-isofs_hash(const struct dentry *dentry, struct qstr *qstr)
-{
- return isofs_hash_common(qstr, 0);
-}
-
static int
isofs_hashi(const struct dentry *dentry, struct qstr *qstr)
{
return isofs_hashi_common(qstr, 0);
}
-static int
-isofs_dentry_cmp(const struct dentry *parent, const struct dentry *dentry,
- unsigned int len, const char *str, const struct qstr *name)
-{
- return isofs_dentry_cmp_common(len, str, name, 0, 0);
-}
-
static int
isofs_dentry_cmpi(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name)
if (opt.check == 'r')
table++;
- s->s_d_op = &isofs_dentry_ops[table];
+ if (table)
+ s->s_d_op = &isofs_dentry_ops[table - 1];
/* get the root dentry */
s->s_root = d_make_root(inode);
isofs_cmp(struct dentry *dentry, const char *compare, int dlen)
{
struct qstr qstr;
-
- if (!compare)
- return 1;
-
- /* check special "." and ".." files */
- if (dlen == 1) {
- /* "." */
- if (compare[0] == 0) {
- if (!dentry->d_name.len)
- return 0;
- compare = ".";
- } else if (compare[0] == 1) {
- compare = "..";
- dlen = 2;
- }
- }
-
qstr.name = compare;
qstr.len = dlen;
+ if (likely(!dentry->d_op))
+ return dentry->d_name.len != dlen || memcmp(dentry->d_name.name, compare, dlen);
return dentry->d_op->d_compare(NULL, NULL, dentry->d_name.len, dentry->d_name.name, &qstr);
}
(!(de->flags[-sbi->s_high_sierra] & 1))) &&
(sbi->s_showassoc ||
(!(de->flags[-sbi->s_high_sierra] & 4)))) {
- match = (isofs_cmp(dentry, dpnt, dlen) == 0);
+ if (dpnt && (dlen > 1 || dpnt[0] > 1))
+ match = (isofs_cmp(dentry, dpnt, dlen) == 0);
}
if (match) {
isofs_normalize_block_and_offset(de,
#include <linux/bio.h>
#endif
#include <linux/log2.h>
+#include <linux/hash.h>
static struct kmem_cache *revoke_record_cache;
static struct kmem_cache *revoke_table_cache;
/* Utility functions to maintain the revoke table */
-/* Borrowed from buffer.c: this is a tried and tested block hash function */
static inline int hash(journal_t *journal, unsigned int block)
{
struct jbd_revoke_table_s *table = journal->j_revoke;
- int hash_shift = table->hash_shift;
- return ((block << (hash_shift - 6)) ^
- (block >> 13) ^
- (block << (hash_shift - 12))) & (table->hash_size - 1);
+ return hash_32(block, table->hash_shift);
}
static int insert_revoke_hash(journal_t *journal, unsigned int blocknr,
#include <linux/init.h>
#include <linux/bio.h>
#include <linux/log2.h>
+#include <linux/hash.h>
#endif
static struct kmem_cache *jbd2_revoke_record_cache;
/* Utility functions to maintain the revoke table */
-/* Borrowed from buffer.c: this is a tried and tested block hash function */
static inline int hash(journal_t *journal, unsigned long long block)
{
- struct jbd2_revoke_table_s *table = journal->j_revoke;
- int hash_shift = table->hash_shift;
- int hash = (int)block ^ (int)((block >> 31) >> 1);
-
- return ((hash << (hash_shift - 6)) ^
- (hash >> 13) ^
- (hash << (hash_shift - 12))) & (table->hash_size - 1);
+ return hash_64(block, journal->j_revoke->hash_shift);
}
static int insert_revoke_hash(journal_t *journal, unsigned long long blocknr,
}
mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT);
- mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_CHILD);
+ mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_PARENT2);
return NULL;
}
EXPORT_SYMBOL(lock_rename);
if (error)
goto out2;
audit_inode(pathname, nd->path.dentry, 0);
- error = may_open(&nd->path, op->acc_mode, op->open_flag);
+ /* Don't check for other permissions, the inode was just created */
+ error = may_open(&nd->path, MAY_OPEN, op->open_flag);
if (error)
goto out2;
file->f_path.mnt = nd->path.mnt;
*/
if (argp->opcnt == resp->opcnt)
return false;
-
+ if (next->opnum == OP_ILLEGAL)
+ return false;
nextd = OPDESC(next);
/*
* Rest of 2.6.3.1.1: certain operations will return WRONGSEC
static inline u32 nfsd4_sequence_rsize(struct svc_rqst *rqstp,
struct nfsd4_op *op)
{
- return NFS4_MAX_SESSIONID_LEN + 20;
+ return (op_encode_hdr_size
+ + XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5) * sizeof(__be32);
}
static inline u32 nfsd4_setattr_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
.op_func = (nfsd4op_func)nfsd4_sequence,
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
.op_name = "OP_SEQUENCE",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_sequence_rsize,
},
[OP_DESTROY_CLIENTID] = {
.op_func = (nfsd4op_func)nfsd4_destroy_clientid,
spin_unlock(&inode->i_lock);
/* In case the dropping of a reference would nuke next_i. */
- if ((&next_i->i_sb_list != list) &&
- atomic_read(&next_i->i_count)) {
+ while (&next_i->i_sb_list != list) {
spin_lock(&next_i->i_lock);
- if (!(next_i->i_state & (I_FREEING | I_WILL_FREE))) {
+ if (!(next_i->i_state & (I_FREEING | I_WILL_FREE)) &&
+ atomic_read(&next_i->i_count)) {
__iget(next_i);
need_iput = next_i;
+ spin_unlock(&next_i->i_lock);
+ break;
}
spin_unlock(&next_i->i_lock);
+ next_i = list_entry(next_i->i_sb_list.next,
+ struct inode, i_sb_list);
}
/*
- * We can safely drop inode_sb_list_lock here because we hold
- * references on both inode and next_i. Also no new inodes
- * will be added since the umount has begun.
+ * We can safely drop inode_sb_list_lock here because either
+ * we actually hold references on both inode and next_i or
+ * end of list. Also no new inodes will be added since the
+ * umount has begun.
*/
spin_unlock(&inode_sb_list_lock);
* NOTE: This dentry already has ->d_op set from
* ocfs2_get_parent() and ocfs2_get_dentry()
*/
- if (ret)
+ if (!IS_ERR_OR_NULL(ret))
dentry = ret;
status = ocfs2_dentry_attach_lock(dentry, inode,
unsigned int len;
unsigned int type;
u64 ino;
- bool is_whiteout;
struct list_head l_node;
struct rb_node node;
+ bool is_whiteout;
+ bool is_cursor;
char name[];
};
p->type = d_type;
p->ino = ino;
p->is_whiteout = false;
+ p->is_cursor = false;
}
return p;
mutex_lock(&dir->d_inode->i_mutex);
list_for_each_entry(p, rdd->list, l_node) {
- if (!p->name)
+ if (p->is_cursor)
continue;
if (p->type != DT_CHR)
}
out:
return err;
-
}
static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos)
loff_t off = 0;
list_for_each_entry(p, &od->cache->entries, l_node) {
- if (!p->name)
+ if (p->is_cursor)
continue;
if (off >= pos)
break;
p = list_entry(od->cursor.l_node.next, struct ovl_cache_entry, l_node);
/* Skip cursors */
- if (p->name) {
+ if (!p->is_cursor) {
if (!p->is_whiteout) {
if (!dir_emit(ctx, p->name, p->len, p->ino, p->type))
break;
if (!od->is_upper && ovl_path_type(dentry) == OVL_PATH_MERGE) {
struct inode *inode = file_inode(file);
- realfile = od->upperfile;
+ realfile =lockless_dereference(od->upperfile);
if (!realfile) {
struct path upperpath;
ovl_path_upper(dentry, &upperpath);
realfile = ovl_path_open(&upperpath, O_RDONLY);
+ smp_mb__before_spinlock();
mutex_lock(&inode->i_mutex);
if (!od->upperfile) {
if (IS_ERR(realfile)) {
od->realfile = realfile;
od->is_real = (type != OVL_PATH_MERGE);
od->is_upper = (type != OVL_PATH_LOWER);
+ od->cursor.is_cursor = true;
file->private_data = od;
return 0;
{
struct ovl_cache_entry *p;
- mutex_lock_nested(&upper->d_inode->i_mutex, I_MUTEX_PARENT);
+ mutex_lock_nested(&upper->d_inode->i_mutex, I_MUTEX_CHILD);
list_for_each_entry(p, list, l_node) {
struct dentry *dentry;
dqstats_inc(DQST_LOOKUPS);
err = sb->dq_op->write_dquot(dquot);
if (!ret && err)
- err = ret;
+ ret = err;
dqput(dquot);
spin_lock(&dq_list_lock);
}
{0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
{0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
{0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
- {0x1002, 0x4C6E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \
{0x1002, 0x4E44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
{0x1002, 0x4E45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
{0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
/*
* tag stuff
*/
-#define blk_rq_tagged(rq) \
- ((rq)->mq_ctx || ((rq)->cmd_flags & REQ_QUEUED))
+#define blk_rq_tagged(rq) ((rq)->cmd_flags & REQ_QUEUED)
extern int blk_queue_start_tag(struct request_queue *, struct request *);
extern struct request *blk_queue_find_tag(struct request_queue *, int);
extern void blk_queue_end_tag(struct request_queue *, struct request *);
struct request *r1,
struct request *r2)
{
- return 0;
+ return true;
}
static inline bool blk_integrity_merge_bio(struct request_queue *rq,
struct request *r,
struct bio *b)
{
- return 0;
+ return true;
}
static inline bool blk_integrity_is_initialized(struct gendisk *g)
{
* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58670
*
* Work it around via a compiler barrier quirk suggested by Jakub Jelinek.
- * Fixed in GCC 4.8.2 and later versions.
*
* (asm goto is automatically volatile - the naming reflects this.)
*/
* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58670
*
* Work it around via a compiler barrier quirk suggested by Jakub Jelinek.
- * Fixed in GCC 4.8.2 and later versions.
*
* (asm goto is automatically volatile - the naming reflects this.)
*/
* 2: child/target
* 3: xattr
* 4: second non-directory
- * The last is for certain operations (such as rename) which lock two
+ * 5: second parent (when locking independent directories in rename)
+ *
+ * I_MUTEX_NONDIR2 is for certain operations (such as rename) which lock two
* non-directories at once.
*
* The locking order between these classes is
- * parent -> child -> normal -> xattr -> second non-directory
+ * parent[2] -> child -> grandchild -> normal -> xattr -> second non-directory
*/
enum inode_i_mutex_lock_class
{
I_MUTEX_PARENT,
I_MUTEX_CHILD,
I_MUTEX_XATTR,
- I_MUTEX_NONDIR2
+ I_MUTEX_NONDIR2,
+ I_MUTEX_PARENT2,
};
void lock_two_nondirectories(struct inode *, struct inode*);
extern ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos);
/* fs/block_dev.c */
+extern ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to);
extern ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from);
extern int blkdev_fsync(struct file *filp, loff_t start, loff_t end,
int datasync);
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
extern int __khugepaged_enter(struct mm_struct *mm);
extern void __khugepaged_exit(struct mm_struct *mm);
-extern int khugepaged_enter_vma_merge(struct vm_area_struct *vma);
+extern int khugepaged_enter_vma_merge(struct vm_area_struct *vma,
+ unsigned long vm_flags);
#define khugepaged_enabled() \
(transparent_hugepage_flags & \
__khugepaged_exit(mm);
}
-static inline int khugepaged_enter(struct vm_area_struct *vma)
+static inline int khugepaged_enter(struct vm_area_struct *vma,
+ unsigned long vm_flags)
{
if (!test_bit(MMF_VM_HUGEPAGE, &vma->vm_mm->flags))
if ((khugepaged_always() ||
- (khugepaged_req_madv() &&
- vma->vm_flags & VM_HUGEPAGE)) &&
- !(vma->vm_flags & VM_NOHUGEPAGE))
+ (khugepaged_req_madv() && (vm_flags & VM_HUGEPAGE))) &&
+ !(vm_flags & VM_NOHUGEPAGE))
if (__khugepaged_enter(vma->vm_mm))
return -ENOMEM;
return 0;
static inline void khugepaged_exit(struct mm_struct *mm)
{
}
-static inline int khugepaged_enter(struct vm_area_struct *vma)
+static inline int khugepaged_enter(struct vm_area_struct *vma,
+ unsigned long vm_flags)
{
return 0;
}
-static inline int khugepaged_enter_vma_merge(struct vm_area_struct *vma)
+static inline int khugepaged_enter_vma_merge(struct vm_area_struct *vma,
+ unsigned long vm_flags)
{
return 0;
}
return false;
}
-void __mem_cgroup_begin_update_page_stat(struct page *page, bool *locked,
- unsigned long *flags);
-
-extern atomic_t memcg_moving;
-
-static inline void mem_cgroup_begin_update_page_stat(struct page *page,
- bool *locked, unsigned long *flags)
-{
- if (mem_cgroup_disabled())
- return;
- rcu_read_lock();
- *locked = false;
- if (atomic_read(&memcg_moving))
- __mem_cgroup_begin_update_page_stat(page, locked, flags);
-}
-
-void __mem_cgroup_end_update_page_stat(struct page *page,
- unsigned long *flags);
-static inline void mem_cgroup_end_update_page_stat(struct page *page,
- bool *locked, unsigned long *flags)
-{
- if (mem_cgroup_disabled())
- return;
- if (*locked)
- __mem_cgroup_end_update_page_stat(page, flags);
- rcu_read_unlock();
-}
-
-void mem_cgroup_update_page_stat(struct page *page,
- enum mem_cgroup_stat_index idx,
- int val);
-
-static inline void mem_cgroup_inc_page_stat(struct page *page,
+struct mem_cgroup *mem_cgroup_begin_page_stat(struct page *page, bool *locked,
+ unsigned long *flags);
+void mem_cgroup_end_page_stat(struct mem_cgroup *memcg, bool locked,
+ unsigned long flags);
+void mem_cgroup_update_page_stat(struct mem_cgroup *memcg,
+ enum mem_cgroup_stat_index idx, int val);
+
+static inline void mem_cgroup_inc_page_stat(struct mem_cgroup *memcg,
enum mem_cgroup_stat_index idx)
{
- mem_cgroup_update_page_stat(page, idx, 1);
+ mem_cgroup_update_page_stat(memcg, idx, 1);
}
-static inline void mem_cgroup_dec_page_stat(struct page *page,
+static inline void mem_cgroup_dec_page_stat(struct mem_cgroup *memcg,
enum mem_cgroup_stat_index idx)
{
- mem_cgroup_update_page_stat(page, idx, -1);
+ mem_cgroup_update_page_stat(memcg, idx, -1);
}
unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
{
}
-static inline void mem_cgroup_begin_update_page_stat(struct page *page,
+static inline struct mem_cgroup *mem_cgroup_begin_page_stat(struct page *page,
bool *locked, unsigned long *flags)
{
+ return NULL;
}
-static inline void mem_cgroup_end_update_page_stat(struct page *page,
- bool *locked, unsigned long *flags)
+static inline void mem_cgroup_end_page_stat(struct mem_cgroup *memcg,
+ bool locked, unsigned long flags)
{
}
return false;
}
-static inline void mem_cgroup_inc_page_stat(struct page *page,
+static inline void mem_cgroup_inc_page_stat(struct mem_cgroup *memcg,
enum mem_cgroup_stat_index idx)
{
}
-static inline void mem_cgroup_dec_page_stat(struct page *page,
+static inline void mem_cgroup_dec_page_stat(struct mem_cgroup *memcg,
enum mem_cgroup_stat_index idx)
{
}
int redirty_page_for_writepage(struct writeback_control *wbc,
struct page *page);
void account_page_dirtied(struct page *page, struct address_space *mapping);
-void account_page_writeback(struct page *page);
int set_page_dirty(struct page *page);
int set_page_dirty_lock(struct page *page);
int clear_page_dirty_for_io(struct page *page);
/**
* spi_nor_scan() - scan the SPI NOR
* @nor: the spi_nor structure
- * @id: the spi_device_id provided by the driver
+ * @name: the chip type name
* @mode: the read mode supported by the driver
*
* The drivers can use this fuction to scan the SPI NOR.
* In the scanning, it will try to get all the necessary information to
* fill the mtd_info{} and the spi_nor{}.
*
- * The board may assigns a spi_device_id with @id which be used to compared with
- * the spi_device_id detected by the scanning.
+ * The chip type name can be provided through the @name parameter.
*
* Return: 0 for success, others for failure.
*/
-int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id,
- enum read_mode mode);
-extern const struct spi_device_id spi_nor_ids[];
-
-/**
- * spi_nor_match_id() - find the spi_device_id by the name
- * @name: the name of the spi_device_id
- *
- * The drivers use this function to find the spi_device_id
- * specified by the @name.
- *
- * Return: returns the right spi_device_id pointer on success,
- * and returns NULL on failure.
- */
-const struct spi_device_id *spi_nor_match_id(char *name);
+int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode);
#endif
};
struct reserved_mem_ops {
- void (*device_init)(struct reserved_mem *rmem,
+ int (*device_init)(struct reserved_mem *rmem,
struct device *dev);
void (*device_release)(struct reserved_mem *rmem,
struct device *dev);
_OF_DECLARE(reservedmem, name, compat, init, reservedmem_of_init_fn)
#ifdef CONFIG_OF_RESERVED_MEM
-void of_reserved_mem_device_init(struct device *dev);
+int of_reserved_mem_device_init(struct device *dev);
void of_reserved_mem_device_release(struct device *dev);
void fdt_init_reserved_mem(void);
void fdt_reserved_mem_save_node(unsigned long node, const char *uname,
phys_addr_t base, phys_addr_t size);
#else
-static inline void of_reserved_mem_device_init(struct device *dev) { }
+static inline int of_reserved_mem_device_init(struct device *dev)
+{
+ return -ENOSYS;
+}
static inline void of_reserved_mem_device_release(struct device *pdev) { }
static inline void fdt_init_reserved_mem(void) { }
*/
#define RCU_INITIALIZER(v) (typeof(*(v)) __force __rcu *)(v)
+/**
+ * lockless_dereference() - safely load a pointer for later dereference
+ * @p: The pointer to load
+ *
+ * Similar to rcu_dereference(), but for situations where the pointed-to
+ * object's lifetime is managed by something other than RCU. That
+ * "something other" might be reference counting or simple immortality.
+ */
+#define lockless_dereference(p) \
+({ \
+ typeof(p) _________p1 = ACCESS_ONCE(p); \
+ smp_read_barrier_depends(); /* Dependency order vs. p above. */ \
+ (_________p1); \
+})
+
/**
* rcu_assign_pointer() - assign to RCU-protected pointer
* @p: pointer to assign to
#ifndef __LINUX_REGULATOR_CONSUMER_H_
#define __LINUX_REGULATOR_CONSUMER_H_
+#include <linux/err.h>
+
struct device;
struct notifier_block;
struct regmap;
/* fields enclosed in headers_start/headers_end are copied
* using a single memcpy() in __copy_skb_header()
*/
+ /* private: */
__u32 headers_start[0];
+ /* public: */
/* if you move pkt_type around you also must adapt those constants */
#ifdef __BIG_ENDIAN_BITFIELD
__u16 network_header;
__u16 mac_header;
+ /* private: */
__u32 headers_end[0];
+ /* public: */
/* These elements must be at the end, see alloc_skb() for details. */
sk_buff_data_t tail;
* @skb: buffer
*
* Returns true is skb is a fast clone, and its clone is not freed.
+ * Some drivers call skb_orphan() in their ndo_start_xmit(),
+ * so we also check that this didnt happen.
*/
-static inline bool skb_fclone_busy(const struct sk_buff *skb)
+static inline bool skb_fclone_busy(const struct sock *sk,
+ const struct sk_buff *skb)
{
const struct sk_buff_fclones *fclones;
fclones = container_of(skb, struct sk_buff_fclones, skb1);
return skb->fclone == SKB_FCLONE_ORIG &&
- fclones->skb2.fclone == SKB_FCLONE_CLONE;
+ fclones->skb2.fclone == SKB_FCLONE_CLONE &&
+ fclones->skb2.sk == sk;
}
static inline struct sk_buff *alloc_skb_fclone(unsigned int size,
# define EVENT_NO_RUNTIME_PM 9
# define EVENT_RX_KILL 10
# define EVENT_LINK_CHANGE 11
+# define EVENT_SET_RX_MODE 12
};
static inline struct usb_driver *driver_of(struct usb_interface *intf)
/* called by minidriver when receiving indication */
void (*indication)(struct usbnet *dev, void *ind, int indlen);
+ /* rx mode change (device changes address list filtering) */
+ void (*set_rx_mode)(struct usbnet *dev);
+
/* for new devices, use the descriptor-reading code instead */
int in; /* rx endpoint */
int out; /* tx endpoint */
return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr));
}
+void ipv6_proxy_select_ident(struct sk_buff *skb);
+
int ip6_dst_hoplimit(struct dst_entry *dst);
static inline int ip6_sk_dst_hoplimit(struct ipv6_pinfo *np, struct flowi6 *fl6,
#ifndef _IPV4_NF_REJECT_H
#define _IPV4_NF_REJECT_H
+#include <linux/skbuff.h>
+#include <net/ip.h>
#include <net/icmp.h>
static inline void nf_send_unreach(struct sk_buff *skb_in, int code)
void nf_send_reset(struct sk_buff *oldskb, int hook);
+const struct tcphdr *nf_reject_ip_tcphdr_get(struct sk_buff *oldskb,
+ struct tcphdr *_oth, int hook);
+struct iphdr *nf_reject_iphdr_put(struct sk_buff *nskb,
+ const struct sk_buff *oldskb,
+ __be16 protocol, int ttl);
+void nf_reject_ip_tcphdr_put(struct sk_buff *nskb, const struct sk_buff *oldskb,
+ const struct tcphdr *oth);
+
#endif /* _IPV4_NF_REJECT_H */
void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook);
+const struct tcphdr *nf_reject_ip6_tcphdr_get(struct sk_buff *oldskb,
+ struct tcphdr *otcph,
+ unsigned int *otcplen, int hook);
+struct ipv6hdr *nf_reject_ip6hdr_put(struct sk_buff *nskb,
+ const struct sk_buff *oldskb,
+ __be16 protocol, int hoplimit);
+void nf_reject_ip6_tcphdr_put(struct sk_buff *nskb,
+ const struct sk_buff *oldskb,
+ const struct tcphdr *oth, unsigned int otcplen);
+
#endif /* _IPV6_NF_REJECT_H */
NFT_CHAIN_T_MAX
};
+int nft_chain_validate_dependency(const struct nft_chain *chain,
+ enum nft_chain_type type);
+
struct nft_stats {
u64 bytes;
u64 pkts;
int nft_masq_dump(struct sk_buff *skb, const struct nft_expr *expr);
+int nft_masq_validate(const struct nft_ctx *ctx, const struct nft_expr *expr,
+ const struct nft_data **data);
+
#endif /* _NFT_MASQ_H_ */
if (!sdev->tagged_supported)
return;
- if (!shost_use_blk_mq(sdev->host) &&
- !blk_queue_tagged(sdev->request_queue))
+ if (shost_use_blk_mq(sdev->host))
+ queue_flag_set_unlocked(QUEUE_FLAG_QUEUED, sdev->request_queue);
+ else if (!blk_queue_tagged(sdev->request_queue))
blk_queue_init_tags(sdev->request_queue, depth,
sdev->host->bqt);
**/
static inline void scsi_deactivate_tcq(struct scsi_device *sdev, int depth)
{
- if (!shost_use_blk_mq(sdev->host) &&
- blk_queue_tagged(sdev->request_queue))
+ if (blk_queue_tagged(sdev->request_queue))
blk_queue_free_tags(sdev->request_queue);
scsi_adjust_queue_depth(sdev, 0, depth);
}
/*
* Tracepoint for _rcu_barrier() execution. The string "s" describes
* the _rcu_barrier phase:
- * "Begin": rcu_barrier_callback() started.
- * "Check": rcu_barrier_callback() checking for piggybacking.
- * "EarlyExit": rcu_barrier_callback() piggybacked, thus early exit.
- * "Inc1": rcu_barrier_callback() piggyback check counter incremented.
- * "Offline": rcu_barrier_callback() found offline CPU
- * "OnlineNoCB": rcu_barrier_callback() found online no-CBs CPU.
- * "OnlineQ": rcu_barrier_callback() found online CPU with callbacks.
- * "OnlineNQ": rcu_barrier_callback() found online CPU, no callbacks.
+ * "Begin": _rcu_barrier() started.
+ * "Check": _rcu_barrier() checking for piggybacking.
+ * "EarlyExit": _rcu_barrier() piggybacked, thus early exit.
+ * "Inc1": _rcu_barrier() piggyback check counter incremented.
+ * "OfflineNoCB": _rcu_barrier() found callback on never-online CPU
+ * "OnlineNoCB": _rcu_barrier() found online no-CBs CPU.
+ * "OnlineQ": _rcu_barrier() found online CPU with callbacks.
+ * "OnlineNQ": _rcu_barrier() found online CPU, no callbacks.
* "IRQ": An rcu_barrier_callback() callback posted on remote CPU.
* "CB": An rcu_barrier_callback() invoked a callback, not the last.
* "LastCB": An rcu_barrier_callback() invoked the last callback.
- * "Inc2": rcu_barrier_callback() piggyback check counter incremented.
+ * "Inc2": _rcu_barrier() piggyback check counter incremented.
* The "cpu" argument is the CPU or -1 if meaningless, the "cnt" argument
* is the count of remaining callbacks, and "done" is the piggybacking count.
*/
#define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */
#define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */
+#define KEY_KBDINPUTASSIST_PREV 0x260
+#define KEY_KBDINPUTASSIST_NEXT 0x261
+#define KEY_KBDINPUTASSIST_PREVGROUP 0x262
+#define KEY_KBDINPUTASSIST_NEXTGROUP 0x263
+#define KEY_KBDINPUTASSIST_ACCEPT 0x264
+#define KEY_KBDINPUTASSIST_CANCEL 0x265
+
#define BTN_TRIGGER_HAPPY 0x2c0
#define BTN_TRIGGER_HAPPY1 0x2c0
#define BTN_TRIGGER_HAPPY2 0x2c1
/*
* Bits needed to read the hw events in user-space.
*
- * u32 seq, time_mult, time_shift, idx, width;
+ * u32 seq, time_mult, time_shift, index, width;
* u64 count, enabled, running;
* u64 cyc, time_offset;
* s64 pmc = 0;
* time_shift = pc->time_shift;
* }
*
- * idx = pc->index;
+ * index = pc->index;
* count = pc->offset;
- * if (pc->cap_usr_rdpmc && idx) {
+ * if (pc->cap_user_rdpmc && index) {
* width = pc->pmc_width;
- * pmc = rdpmc(idx - 1);
+ * pmc = rdpmc(index - 1);
* }
*
* barrier();
};
/*
- * If cap_usr_rdpmc this field provides the bit-width of the value
+ * If cap_user_rdpmc this field provides the bit-width of the value
* read using the rdpmc() or equivalent instruction. This can be used
* to sign extend the result like:
*
*
* Where time_offset,time_mult,time_shift and cyc are read in the
* seqcount loop described above. This delta can then be added to
- * enabled and possible running (if idx), improving the scaling:
+ * enabled and possible running (if index), improving the scaling:
*
* enabled += delta;
- * if (idx)
+ * if (index)
* running += delta;
*
* quot = count / running;
#define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wake it up on mm_release */
#define CLONE_PARENT 0x00008000 /* set if we want to have the same parent as the cloner */
#define CLONE_THREAD 0x00010000 /* Same thread group? */
-#define CLONE_NEWNS 0x00020000 /* New namespace group? */
+#define CLONE_NEWNS 0x00020000 /* New mount namespace group */
#define CLONE_SYSVSEM 0x00040000 /* share system V SEM_UNDO semantics */
#define CLONE_SETTLS 0x00080000 /* create a new TLS for the child */
#define CLONE_PARENT_SETTID 0x00100000 /* set the TID in the parent */
#ifndef _V4L2_DV_TIMINGS_H
#define _V4L2_DV_TIMINGS_H
+#if __GNUC__ < 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ < 6))
+/* Sadly gcc versions older than 4.6 have a bug in how they initialize
+ anonymous unions where they require additional curly brackets.
+ This violates the C1x standard. This workaround adds the curly brackets
+ if needed. */
#define V4L2_INIT_BT_TIMINGS(_width, args...) \
{ .bt = { _width , ## args } }
+#else
+#define V4L2_INIT_BT_TIMINGS(_width, args...) \
+ .bt = { _width , ## args }
+#endif
/* CEA-861-E timings (i.e. standard HDTV timings) */
config HAVE_PCSPKR_PLATFORM
bool
+# interpreter that classic socket filters depend on
+config BPF
+ bool
+
menuconfig EXPERT
bool "Configure standard kernel features (expert users)"
# Unhide debug options, to make the on-by-default options visible
If unsure, say Y.
+# syscall, maps, verifier
+config BPF_SYSCALL
+ bool "Enable bpf() system call" if EXPERT
+ select ANON_INODES
+ select BPF
+ default n
+ help
+ Enable the bpf() system call that allows to manipulate eBPF
+ programs and maps via file descriptors.
+
config SHMEM
bool "Use full shmem filesystem" if EXPERT
default y
obj-$(CONFIG_TRACEPOINTS) += trace/
obj-$(CONFIG_IRQ_WORK) += irq_work.o
obj-$(CONFIG_CPU_PM) += cpu_pm.o
-obj-$(CONFIG_NET) += bpf/
+obj-$(CONFIG_BPF) += bpf/
obj-$(CONFIG_PERF_EVENTS) += events/
-obj-y := core.o syscall.o verifier.o
-
+obj-y := core.o
+obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o
ifdef CONFIG_TEST_BPF
-obj-y += test_stub.o
+obj-$(CONFIG_BPF_SYSCALL) += test_stub.o
endif
schedule_work(&aux->work);
}
EXPORT_SYMBOL_GPL(bpf_prog_free);
+
+/* To execute LD_ABS/LD_IND instructions __bpf_prog_run() may call
+ * skb_copy_bits(), so provide a weak definition of it for NET-less config.
+ */
+int __weak skb_copy_bits(const struct sk_buff *skb, int offset, void *to,
+ int len)
+{
+ return -EFAULT;
+}
if (memcmp(&old->regs[i], &cur->regs[i],
sizeof(old->regs[0])) != 0) {
if (old->regs[i].type == NOT_INIT ||
- old->regs[i].type == UNKNOWN_VALUE)
+ (old->regs[i].type == UNKNOWN_VALUE &&
+ cur->regs[i].type != NOT_INIT))
continue;
return false;
}
}
NOKPROBE_SYMBOL(context_tracking_user_enter);
-#ifdef CONFIG_PREEMPT
-/**
- * preempt_schedule_context - preempt_schedule called by tracing
- *
- * The tracing infrastructure uses preempt_enable_notrace to prevent
- * recursion and tracing preempt enabling caused by the tracing
- * infrastructure itself. But as tracing can happen in areas coming
- * from userspace or just about to enter userspace, a preempt enable
- * can occur before user_exit() is called. This will cause the scheduler
- * to be called when the system is still in usermode.
- *
- * To prevent this, the preempt_enable_notrace will use this function
- * instead of preempt_schedule() to exit user context if needed before
- * calling the scheduler.
- */
-asmlinkage __visible void __sched notrace preempt_schedule_context(void)
-{
- enum ctx_state prev_ctx;
-
- if (likely(!preemptible()))
- return;
-
- /*
- * Need to disable preemption in case user_exit() is traced
- * and the tracer calls preempt_enable_notrace() causing
- * an infinite recursion.
- */
- preempt_disable_notrace();
- prev_ctx = exception_enter();
- preempt_enable_no_resched_notrace();
-
- preempt_schedule();
-
- preempt_disable_notrace();
- exception_exit(prev_ctx);
- preempt_enable_notrace();
-}
-EXPORT_SYMBOL_GPL(preempt_schedule_context);
-#endif /* CONFIG_PREEMPT */
-
/**
* context_tracking_user_exit - Inform the context tracking that the CPU is
* exiting userspace mode and entering the kernel.
* an ongoing cpu hotplug operation.
*/
int refcount;
+ /* And allows lockless put_online_cpus(). */
+ atomic_t puts_pending;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
{
if (cpu_hotplug.active_writer == current)
return;
- mutex_lock(&cpu_hotplug.lock);
+ if (!mutex_trylock(&cpu_hotplug.lock)) {
+ atomic_inc(&cpu_hotplug.puts_pending);
+ cpuhp_lock_release();
+ return;
+ }
if (WARN_ON(!cpu_hotplug.refcount))
cpu_hotplug.refcount++; /* try to fix things up */
cpuhp_lock_acquire();
for (;;) {
mutex_lock(&cpu_hotplug.lock);
+ if (atomic_read(&cpu_hotplug.puts_pending)) {
+ int delta;
+
+ delta = atomic_xchg(&cpu_hotplug.puts_pending, 0);
+ cpu_hotplug.refcount -= delta;
+ }
if (likely(!cpu_hotplug.refcount))
break;
__set_current_state(TASK_UNINTERRUPTIBLE);
return 0;
}
-static int perf_swevent_event_idx(struct perf_event *event)
-{
- return 0;
-}
-
static struct pmu perf_swevent = {
.task_ctx_nr = perf_sw_context,
.start = perf_swevent_start,
.stop = perf_swevent_stop,
.read = perf_swevent_read,
-
- .event_idx = perf_swevent_event_idx,
};
#ifdef CONFIG_EVENT_TRACING
.start = perf_swevent_start,
.stop = perf_swevent_stop,
.read = perf_swevent_read,
-
- .event_idx = perf_swevent_event_idx,
};
static inline void perf_tp_register(void)
.start = cpu_clock_event_start,
.stop = cpu_clock_event_stop,
.read = cpu_clock_event_read,
-
- .event_idx = perf_swevent_event_idx,
};
/*
.start = task_clock_event_start,
.stop = task_clock_event_stop,
.read = task_clock_event_read,
-
- .event_idx = perf_swevent_event_idx,
};
static void perf_pmu_nop_void(struct pmu *pmu)
static int perf_event_idx_default(struct perf_event *event)
{
- return event->hw.idx + 1;
+ return 0;
}
/*
bp->hw.state = PERF_HES_STOPPED;
}
-static int hw_breakpoint_event_idx(struct perf_event *bp)
-{
- return 0;
-}
-
static struct pmu perf_breakpoint = {
.task_ctx_nr = perf_sw_context, /* could eventually get its own */
.start = hw_breakpoint_start,
.stop = hw_breakpoint_stop,
.read = hw_breakpoint_pmu_read,
-
- .event_idx = hw_breakpoint_event_idx,
};
int __init init_hw_breakpoint(void)
*
* Where (A) orders the waiters increment and the futex value read through
* atomic operations (see hb_waiters_inc) and where (B) orders the write
- * to futex and the waiters read -- this is done by the barriers in
- * get_futex_key_refs(), through either ihold or atomic_inc, depending on the
- * futex type.
+ * to futex and the waiters read -- this is done by the barriers for both
+ * shared and private futexes in get_futex_key_refs().
*
* This yields the following case (where X:=waiters, Y:=futex):
*
futex_get_mm(key); /* implies MB (B) */
break;
default:
+ /*
+ * Private futexes do not hold reference on an inode or
+ * mm, therefore the only purpose of calling get_futex_key_refs
+ * is because we need the barrier for the lockless waiter check.
+ */
smp_mb(); /* explicit MB (B) */
}
}
/*
* Drop a reference to the resource addressed by a key.
- * The hash bucket spinlock must not be held.
+ * The hash bucket spinlock must not be held. This is
+ * a no-op for private futexes, see comment in the get
+ * counterpart.
*/
static void drop_futex_key_refs(union futex_key *key)
{
return pi_state;
}
+/*
+ * Must be called with the hb lock held.
+ */
static void free_pi_state(struct futex_pi_state *pi_state)
{
+ if (!pi_state)
+ return;
+
if (!atomic_dec_and_test(&pi_state->refcount))
return;
}
retry:
- if (pi_state != NULL) {
- /*
- * We will have to lookup the pi_state again, so free this one
- * to keep the accounting correct.
- */
- free_pi_state(pi_state);
- pi_state = NULL;
- }
-
ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, VERIFY_READ);
if (unlikely(ret != 0))
goto out;
case 0:
break;
case -EFAULT:
+ free_pi_state(pi_state);
+ pi_state = NULL;
double_unlock_hb(hb1, hb2);
hb_waiters_dec(hb2);
put_futex_key(&key2);
* exit to complete.
* - The user space value changed.
*/
+ free_pi_state(pi_state);
+ pi_state = NULL;
double_unlock_hb(hb1, hb2);
hb_waiters_dec(hb2);
put_futex_key(&key2);
}
out_unlock:
+ free_pi_state(pi_state);
double_unlock_hb(hb1, hb2);
hb_waiters_dec(hb2);
out_put_key1:
put_futex_key(&key1);
out:
- if (pi_state != NULL)
- free_pi_state(pi_state);
return ret ? ret : task_count;
}
config GCOV_PROFILE_ALL
bool "Profile entire Kernel"
depends on GCOV_KERNEL
- depends on SUPERH || S390 || X86 || PPC || MICROBLAZE || ARM
+ depends on SUPERH || S390 || X86 || PPC || MICROBLAZE || ARM || ARM64
default n
---help---
This options activates profiling for the entire kernel.
EXPORT_SYMBOL(__request_module);
#endif /* CONFIG_MODULES */
+static void call_usermodehelper_freeinfo(struct subprocess_info *info)
+{
+ if (info->cleanup)
+ (*info->cleanup)(info);
+ kfree(info);
+}
+
+static void umh_complete(struct subprocess_info *sub_info)
+{
+ struct completion *comp = xchg(&sub_info->complete, NULL);
+ /*
+ * See call_usermodehelper_exec(). If xchg() returns NULL
+ * we own sub_info, the UMH_KILLABLE caller has gone away
+ * or the caller used UMH_NO_WAIT.
+ */
+ if (comp)
+ complete(comp);
+ else
+ call_usermodehelper_freeinfo(sub_info);
+}
+
/*
* This is the task which runs the usermode application
*/
static int ____call_usermodehelper(void *data)
{
struct subprocess_info *sub_info = data;
+ int wait = sub_info->wait & ~UMH_KILLABLE;
struct cred *new;
int retval;
retval = -ENOMEM;
new = prepare_kernel_cred(current);
if (!new)
- goto fail;
+ goto out;
spin_lock(&umh_sysctl_lock);
new->cap_bset = cap_intersect(usermodehelper_bset, new->cap_bset);
retval = sub_info->init(sub_info, new);
if (retval) {
abort_creds(new);
- goto fail;
+ goto out;
}
}
retval = do_execve(getname_kernel(sub_info->path),
(const char __user *const __user *)sub_info->argv,
(const char __user *const __user *)sub_info->envp);
+out:
+ sub_info->retval = retval;
+ /* wait_for_helper() will call umh_complete if UHM_WAIT_PROC. */
+ if (wait != UMH_WAIT_PROC)
+ umh_complete(sub_info);
if (!retval)
return 0;
-
- /* Exec failed? */
-fail:
- sub_info->retval = retval;
do_exit(0);
}
return ____call_usermodehelper(data);
}
-static void call_usermodehelper_freeinfo(struct subprocess_info *info)
-{
- if (info->cleanup)
- (*info->cleanup)(info);
- kfree(info);
-}
-
-static void umh_complete(struct subprocess_info *sub_info)
-{
- struct completion *comp = xchg(&sub_info->complete, NULL);
- /*
- * See call_usermodehelper_exec(). If xchg() returns NULL
- * we own sub_info, the UMH_KILLABLE caller has gone away.
- */
- if (comp)
- complete(comp);
- else
- call_usermodehelper_freeinfo(sub_info);
-}
-
/* Keventd can't block, but this (a child) can. */
static int wait_for_helper(void *data)
{
kmod_thread_locker = NULL;
}
- switch (wait) {
- case UMH_NO_WAIT:
- call_usermodehelper_freeinfo(sub_info);
- break;
-
- case UMH_WAIT_PROC:
- if (pid > 0)
- break;
- /* FALLTHROUGH */
- case UMH_WAIT_EXEC:
- if (pid < 0)
- sub_info->retval = pid;
+ if (pid < 0) {
+ sub_info->retval = pid;
umh_complete(sub_info);
}
}
goto out;
}
- sub_info->complete = &done;
+ /*
+ * Set the completion pointer only if there is a waiter.
+ * This makes it possible to use umh_complete to free
+ * the data structure in case of UMH_NO_WAIT.
+ */
+ sub_info->complete = (wait == UMH_NO_WAIT) ? NULL : &done;
sub_info->wait = wait;
queue_work(khelper_wq, &sub_info->work);
error = dpm_suspend_start(PMSG_QUIESCE);
if (!error) {
error = resume_target_kernel(platform_mode);
- dpm_resume_end(PMSG_RECOVER);
+ /*
+ * The above should either succeed and jump to the new kernel,
+ * or return with an error. Otherwise things are just
+ * undefined, so let's be paranoid.
+ */
+ BUG_ON(!error);
}
+ dpm_resume_end(PMSG_RECOVER);
pm_restore_gfp_mask();
resume_console();
pm_restore_console();
continue;
rdp = per_cpu_ptr(rsp->rda, cpu);
if (rcu_is_nocb_cpu(cpu)) {
- _rcu_barrier_trace(rsp, "OnlineNoCB", cpu,
- rsp->n_barrier_done);
- atomic_inc(&rsp->barrier_cpu_count);
- __call_rcu(&rdp->barrier_head, rcu_barrier_callback,
- rsp, cpu, 0);
+ if (!rcu_nocb_cpu_needs_barrier(rsp, cpu)) {
+ _rcu_barrier_trace(rsp, "OfflineNoCB", cpu,
+ rsp->n_barrier_done);
+ } else {
+ _rcu_barrier_trace(rsp, "OnlineNoCB", cpu,
+ rsp->n_barrier_done);
+ atomic_inc(&rsp->barrier_cpu_count);
+ __call_rcu(&rdp->barrier_head,
+ rcu_barrier_callback, rsp, cpu, 0);
+ }
} else if (ACCESS_ONCE(rdp->qlen)) {
_rcu_barrier_trace(rsp, "OnlineQ", cpu,
rsp->n_barrier_done);
static void print_cpu_stall_info_end(void);
static void zero_cpu_stall_ticks(struct rcu_data *rdp);
static void increment_cpu_stall_ticks(void);
+static bool rcu_nocb_cpu_needs_barrier(struct rcu_state *rsp, int cpu);
static void rcu_nocb_gp_set(struct rcu_node *rnp, int nrq);
static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp);
static void rcu_init_one_nocb(struct rcu_node *rnp);
}
}
+/*
+ * Does the specified CPU need an RCU callback for the specified flavor
+ * of rcu_barrier()?
+ */
+static bool rcu_nocb_cpu_needs_barrier(struct rcu_state *rsp, int cpu)
+{
+ struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);
+ struct rcu_head *rhp;
+
+ /* No-CBs CPUs might have callbacks on any of three lists. */
+ rhp = ACCESS_ONCE(rdp->nocb_head);
+ if (!rhp)
+ rhp = ACCESS_ONCE(rdp->nocb_gp_head);
+ if (!rhp)
+ rhp = ACCESS_ONCE(rdp->nocb_follower_head);
+
+ /* Having no rcuo kthread but CBs after scheduler starts is bad! */
+ if (!ACCESS_ONCE(rdp->nocb_kthread) && rhp) {
+ /* RCU callback enqueued before CPU first came online??? */
+ pr_err("RCU: Never-onlined no-CBs CPU %d has CB %p\n",
+ cpu, rhp->func);
+ WARN_ON_ONCE(1);
+ }
+
+ return !!rhp;
+}
+
/*
* Enqueue the specified string of rcu_head structures onto the specified
* CPU's no-CBs lists. The CPU is specified by rdp, the head of the
#else /* #ifdef CONFIG_RCU_NOCB_CPU */
+static bool rcu_nocb_cpu_needs_barrier(struct rcu_state *rsp, int cpu)
+{
+ WARN_ON_ONCE(1); /* Should be dead code. */
+ return false;
+}
+
static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp)
{
}
}
NOKPROBE_SYMBOL(preempt_schedule);
EXPORT_SYMBOL(preempt_schedule);
+
+#ifdef CONFIG_CONTEXT_TRACKING
+/**
+ * preempt_schedule_context - preempt_schedule called by tracing
+ *
+ * The tracing infrastructure uses preempt_enable_notrace to prevent
+ * recursion and tracing preempt enabling caused by the tracing
+ * infrastructure itself. But as tracing can happen in areas coming
+ * from userspace or just about to enter userspace, a preempt enable
+ * can occur before user_exit() is called. This will cause the scheduler
+ * to be called when the system is still in usermode.
+ *
+ * To prevent this, the preempt_enable_notrace will use this function
+ * instead of preempt_schedule() to exit user context if needed before
+ * calling the scheduler.
+ */
+asmlinkage __visible void __sched notrace preempt_schedule_context(void)
+{
+ enum ctx_state prev_ctx;
+
+ if (likely(!preemptible()))
+ return;
+
+ do {
+ __preempt_count_add(PREEMPT_ACTIVE);
+ /*
+ * Needs preempt disabled in case user_exit() is traced
+ * and the tracer calls preempt_enable_notrace() causing
+ * an infinite recursion.
+ */
+ prev_ctx = exception_enter();
+ __schedule();
+ exception_exit(prev_ctx);
+
+ __preempt_count_sub(PREEMPT_ACTIVE);
+ barrier();
+ } while (need_resched());
+}
+EXPORT_SYMBOL_GPL(preempt_schedule_context);
+#endif /* CONFIG_CONTEXT_TRACKING */
+
#endif /* CONFIG_PREEMPT */
/*
sched_offline_group(tg);
}
+static void cpu_cgroup_fork(struct task_struct *task)
+{
+ sched_move_task(task);
+}
+
static int cpu_cgroup_can_attach(struct cgroup_subsys_state *css,
struct cgroup_taskset *tset)
{
.css_free = cpu_cgroup_css_free,
.css_online = cpu_cgroup_css_online,
.css_offline = cpu_cgroup_css_offline,
+ .fork = cpu_cgroup_fork,
.can_attach = cpu_cgroup_can_attach,
.attach = cpu_cgroup_attach,
.exit = cpu_cgroup_exit,
}
/*
- * We need to take care of a possible races here. In fact, the
- * task might have changed its scheduling policy to something
- * different from SCHED_DEADLINE or changed its reservation
- * parameters (through sched_setattr()).
+ * We need to take care of several possible races here:
+ *
+ * - the task might have changed its scheduling policy
+ * to something different than SCHED_DEADLINE
+ * - the task might have changed its reservation parameters
+ * (through sched_setattr())
+ * - the task might have been boosted by someone else and
+ * might be in the boosting/deboosting path
+ *
+ * In all this cases we bail out, as the task is already
+ * in the runqueue or is going to be enqueued back anyway.
*/
- if (!dl_task(p) || dl_se->dl_new)
+ if (!dl_task(p) || dl_se->dl_new ||
+ dl_se->dl_boosted || !dl_se->dl_throttled)
goto unlock;
sched_clock_tick();
dl_se->dl_yielded = 0;
if (task_on_rq_queued(p)) {
enqueue_task_dl(rq, p, ENQUEUE_REPLENISH);
- if (task_has_dl_policy(rq->curr))
+ if (dl_task(rq->curr))
check_preempt_curr_dl(rq, p, 0);
else
resched_curr(rq);
* smaller than our one... OTW we keep our runtime and
* deadline.
*/
- if (pi_task && p->dl.dl_boosted && dl_prio(pi_task->normal_prio))
+ if (pi_task && p->dl.dl_boosted && dl_prio(pi_task->normal_prio)) {
pi_se = &pi_task->dl;
+ } else if (!dl_prio(p->normal_prio)) {
+ /*
+ * Special case in which we have a !SCHED_DEADLINE task
+ * that is going to be deboosted, but exceedes its
+ * runtime while doing so. No point in replenishing
+ * it, as it's going to return back to its original
+ * scheduling class after this.
+ */
+ BUG_ON(!p->dl.dl_boosted || flags != ENQUEUE_REPLENISH);
+ return;
+ }
/*
* If p is throttled, we do nothing. In fact, if it exhausted
/* Only reschedule if pushing failed */
check_resched = 0;
#endif /* CONFIG_SMP */
- if (check_resched && task_has_dl_policy(rq->curr))
- check_preempt_curr_dl(rq, p, 0);
+ if (check_resched) {
+ if (dl_task(rq->curr))
+ check_preempt_curr_dl(rq, p, 0);
+ else
+ resched_curr(rq);
+ }
}
}
static unsigned int task_scan_min(struct task_struct *p)
{
+ unsigned int scan_size = ACCESS_ONCE(sysctl_numa_balancing_scan_size);
unsigned int scan, floor;
unsigned int windows = 1;
- if (sysctl_numa_balancing_scan_size < MAX_SCAN_WINDOW)
- windows = MAX_SCAN_WINDOW / sysctl_numa_balancing_scan_size;
+ if (scan_size < MAX_SCAN_WINDOW)
+ windows = MAX_SCAN_WINDOW / scan_size;
floor = 1000 / windows;
scan = sysctl_numa_balancing_scan_period_min / task_nr_scan_windows(p);
long moveimp = imp;
rcu_read_lock();
- cur = ACCESS_ONCE(dst_rq->curr);
- if (cur->pid == 0) /* idle */
+
+ raw_spin_lock_irq(&dst_rq->lock);
+ cur = dst_rq->curr;
+ /*
+ * No need to move the exiting task, and this ensures that ->curr
+ * wasn't reaped and thus get_task_struct() in task_numa_assign()
+ * is safe under RCU read lock.
+ * Note that rcu_read_lock() itself can't protect from the final
+ * put_task_struct() after the last schedule().
+ */
+ if ((cur->flags & PF_EXITING) || is_idle_task(cur))
cur = NULL;
+ raw_spin_unlock_irq(&dst_rq->lock);
/*
* "imp" is the fault differential for the source task between the
* scanning faster if shared accesses dominate as it may
* simply bounce migrations uselessly
*/
- ratio = DIV_ROUND_UP(private * NUMA_PERIOD_SLOTS, (private + shared));
+ ratio = DIV_ROUND_UP(private * NUMA_PERIOD_SLOTS, (private + shared + 1));
diff = (diff * ratio) / NUMA_PERIOD_SLOTS;
}
.data = &sysctl_numa_balancing_scan_size,
.maxlen = sizeof(unsigned int),
.mode = 0644,
- .proc_handler = proc_dointvec,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &one,
},
{
.procname = "numa_balancing",
* Also omit the add if it would overflow the u64 boundary.
*/
if ((~0ULL - clc > rnd) &&
- (!ismax || evt->mult <= (1U << evt->shift)))
+ (!ismax || evt->mult <= (1ULL << evt->shift)))
clc += rnd;
do_div(clc, evt->mult);
goto out;
}
} else {
+ memset(&event.sigev_value, 0, sizeof(event.sigev_value));
event.sigev_notify = SIGEV_SIGNAL;
event.sigev_signo = SIGALRM;
event.sigev_value.sival_int = new_timer->it_id;
* when we are adding another op to the rec or removing the
* current one. Thus, if the op is being added, we can
* ignore it because it hasn't attached itself to the rec
- * yet. That means we just need to find the op that has a
- * trampoline and is not beeing added.
+ * yet.
+ *
+ * If an ops is being modified (hooking to different functions)
+ * then we don't care about the new functions that are being
+ * added, just the old ones (that are probably being removed).
+ *
+ * If we are adding an ops to a function that already is using
+ * a trampoline, it needs to be removed (trampolines are only
+ * for single ops connected), then an ops that is not being
+ * modified also needs to be checked.
*/
do_for_each_ftrace_op(op, ftrace_ops_list) {
if (op->flags & FTRACE_OPS_FL_ADDING)
continue;
+
/*
- * If the ops is not being added and has a trampoline,
- * then it must be the one that we want!
+ * If the ops is being modified and is in the old
+ * hash, then it is probably being removed from this
+ * function.
*/
- if (hash_contains_ip(ip, op->func_hash))
- return op;
-
- /* If the ops is being modified, it may be in the old hash. */
if ((op->flags & FTRACE_OPS_FL_MODIFYING) &&
hash_contains_ip(ip, &op->old_hash))
return op;
+ /*
+ * If the ops is not being added or modified, and it's
+ * in its normal filter hash, then this must be the one
+ * we want!
+ */
+ if (!(op->flags & FTRACE_OPS_FL_MODIFYING) &&
+ hash_contains_ip(ip, op->func_hash))
+ return op;
} while_for_each_ftrace_op(op);
FTRACE_WARN_ON(ret);
}
-static void ftrace_run_modify_code(struct ftrace_ops *ops, int command)
+static void ftrace_run_modify_code(struct ftrace_ops *ops, int command,
+ struct ftrace_hash *old_hash)
{
ops->flags |= FTRACE_OPS_FL_MODIFYING;
+ ops->old_hash.filter_hash = old_hash;
ftrace_run_update_code(command);
+ ops->old_hash.filter_hash = NULL;
ops->flags &= ~FTRACE_OPS_FL_MODIFYING;
}
static int ftrace_probe_registered;
-static void __enable_ftrace_function_probe(void)
+static void __enable_ftrace_function_probe(struct ftrace_hash *old_hash)
{
int ret;
int i;
if (ftrace_probe_registered) {
/* still need to update the function call sites */
if (ftrace_enabled)
- ftrace_run_modify_code(&trace_probe_ops, FTRACE_UPDATE_CALLS);
+ ftrace_run_modify_code(&trace_probe_ops, FTRACE_UPDATE_CALLS,
+ old_hash);
return;
}
} while_for_each_ftrace_rec();
ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash);
+
+ __enable_ftrace_function_probe(old_hash);
+
if (!ret)
free_ftrace_hash_rcu(old_hash);
else
count = ret;
- __enable_ftrace_function_probe();
-
out_unlock:
mutex_unlock(&ftrace_lock);
out:
return add_hash_entry(hash, ip);
}
-static void ftrace_ops_update_code(struct ftrace_ops *ops)
+static void ftrace_ops_update_code(struct ftrace_ops *ops,
+ struct ftrace_hash *old_hash)
{
if (ops->flags & FTRACE_OPS_FL_ENABLED && ftrace_enabled)
- ftrace_run_modify_code(ops, FTRACE_UPDATE_CALLS);
+ ftrace_run_modify_code(ops, FTRACE_UPDATE_CALLS, old_hash);
}
static int
old_hash = *orig_hash;
ret = ftrace_hash_move(ops, enable, orig_hash, hash);
if (!ret) {
- ftrace_ops_update_code(ops);
+ ftrace_ops_update_code(ops, old_hash);
free_ftrace_hash_rcu(old_hash);
}
mutex_unlock(&ftrace_lock);
ret = ftrace_hash_move(iter->ops, filter_hash,
orig_hash, iter->hash);
if (!ret) {
- ftrace_ops_update_code(iter->ops);
+ ftrace_ops_update_code(iter->ops, old_hash);
free_ftrace_hash_rcu(old_hash);
}
mutex_unlock(&ftrace_lock);
int size;
syscall_nr = trace_get_syscall_nr(current, regs);
- if (syscall_nr < 0)
+ if (syscall_nr < 0 || syscall_nr >= NR_syscalls)
return;
/* Here we're inside tp handler's rcu_read_lock_sched (__DO_TRACE) */
int syscall_nr;
syscall_nr = trace_get_syscall_nr(current, regs);
- if (syscall_nr < 0)
+ if (syscall_nr < 0 || syscall_nr >= NR_syscalls)
return;
/* Here we're inside tp handler's rcu_read_lock_sched (__DO_TRACE()) */
int size;
syscall_nr = trace_get_syscall_nr(current, regs);
- if (syscall_nr < 0)
+ if (syscall_nr < 0 || syscall_nr >= NR_syscalls)
return;
if (!test_bit(syscall_nr, enabled_perf_enter_syscalls))
return;
int size;
syscall_nr = trace_get_syscall_nr(current, regs);
- if (syscall_nr < 0)
+ if (syscall_nr < 0 || syscall_nr >= NR_syscalls)
return;
if (!test_bit(syscall_nr, enabled_perf_exit_syscalls))
return;
lower = src[off + k];
if (left && off + k == lim - 1)
lower &= mask;
- dst[k] = upper << (BITS_PER_LONG - rem) | lower >> rem;
+ dst[k] = lower >> rem;
+ if (rem)
+ dst[k] |= upper << (BITS_PER_LONG - rem);
if (left && k == lim - 1)
dst[k] &= mask;
}
upper = src[k];
if (left && k == lim - 1)
upper &= (1UL << left) - 1;
- dst[k + off] = lower >> (BITS_PER_LONG - rem) | upper << rem;
+ dst[k + off] = upper << rem;
+ if (rem)
+ dst[k + off] |= lower >> (BITS_PER_LONG - rem);
if (left && k + off == lim - 1)
dst[k + off] &= (1UL << left) - 1;
}
}
table->orig_nents -= sg_size;
- if (!skip_first_chunk) {
- free_fn(sgl, alloc_size);
+ if (skip_first_chunk)
skip_first_chunk = false;
- }
+ else
+ free_fn(sgl, alloc_size);
sgl = next;
}
* to be released by the balloon driver.
*/
if (trylock_page(page)) {
+#ifdef CONFIG_BALLOON_COMPACTION
if (!PagePrivate(page)) {
/* raced with isolation */
unlock_page(page);
continue;
}
+#endif
spin_lock_irqsave(&b_dev_info->pages_lock, flags);
balloon_page_delete(page);
__count_vm_event(BALLOON_DEFLATE);
cc->nr_migratepages = 0;
break;
}
+
+ if (cc->nr_migratepages == COMPACT_CLUSTER_MAX)
+ break;
}
acct_isolated(cc->zone, cc);
preempt_disable();
if (cmpxchg(&huge_zero_page, NULL, zero_page)) {
preempt_enable();
- __free_page(zero_page);
+ __free_pages(zero_page, compound_order(zero_page));
goto retry;
}
if (atomic_cmpxchg(&huge_zero_refcount, 1, 0) == 1) {
struct page *zero_page = xchg(&huge_zero_page, NULL);
BUG_ON(zero_page == NULL);
- __free_page(zero_page);
+ __free_pages(zero_page, compound_order(zero_page));
return HPAGE_PMD_NR;
}
return VM_FAULT_FALLBACK;
if (unlikely(anon_vma_prepare(vma)))
return VM_FAULT_OOM;
- if (unlikely(khugepaged_enter(vma)))
+ if (unlikely(khugepaged_enter(vma, vma->vm_flags)))
return VM_FAULT_OOM;
if (!(flags & FAULT_FLAG_WRITE) &&
transparent_hugepage_use_zero_page()) {
* register it here without waiting a page fault that
* may not happen any time soon.
*/
- if (unlikely(khugepaged_enter_vma_merge(vma)))
+ if (unlikely(khugepaged_enter_vma_merge(vma, *vm_flags)))
return -ENOMEM;
break;
case MADV_NOHUGEPAGE:
return 0;
}
-int khugepaged_enter_vma_merge(struct vm_area_struct *vma)
+int khugepaged_enter_vma_merge(struct vm_area_struct *vma,
+ unsigned long vm_flags)
{
unsigned long hstart, hend;
if (!vma->anon_vma)
if (vma->vm_ops)
/* khugepaged not yet working on file or special mappings */
return 0;
- VM_BUG_ON_VMA(vma->vm_flags & VM_NO_THP, vma);
+ VM_BUG_ON_VMA(vm_flags & VM_NO_THP, vma);
hstart = (vma->vm_start + ~HPAGE_PMD_MASK) & HPAGE_PMD_MASK;
hend = vma->vm_end & HPAGE_PMD_MASK;
if (hstart < hend)
- return khugepaged_enter(vma);
+ return khugepaged_enter(vma, vm_flags);
return 0;
}
* start move here.
*/
-/* for quick checking without looking up memcg */
-atomic_t memcg_moving __read_mostly;
-
static void mem_cgroup_start_move(struct mem_cgroup *memcg)
{
- atomic_inc(&memcg_moving);
atomic_inc(&memcg->moving_account);
synchronize_rcu();
}
* Now, mem_cgroup_clear_mc() may call this function with NULL.
* We check NULL in callee rather than caller.
*/
- if (memcg) {
- atomic_dec(&memcg_moving);
+ if (memcg)
atomic_dec(&memcg->moving_account);
- }
}
/*
return true;
}
-/*
- * Used to update mapped file or writeback or other statistics.
+/**
+ * mem_cgroup_begin_page_stat - begin a page state statistics transaction
+ * @page: page that is going to change accounted state
+ * @locked: &memcg->move_lock slowpath was taken
+ * @flags: IRQ-state flags for &memcg->move_lock
*
- * Notes: Race condition
+ * This function must mark the beginning of an accounted page state
+ * change to prevent double accounting when the page is concurrently
+ * being moved to another memcg:
*
- * Charging occurs during page instantiation, while the page is
- * unmapped and locked in page migration, or while the page table is
- * locked in THP migration. No race is possible.
+ * memcg = mem_cgroup_begin_page_stat(page, &locked, &flags);
+ * if (TestClearPageState(page))
+ * mem_cgroup_update_page_stat(memcg, state, -1);
+ * mem_cgroup_end_page_stat(memcg, locked, flags);
*
- * Uncharge happens to pages with zero references, no race possible.
+ * The RCU lock is held throughout the transaction. The fast path can
+ * get away without acquiring the memcg->move_lock (@locked is false)
+ * because page moving starts with an RCU grace period.
*
- * Charge moving between groups is protected by checking mm->moving
- * account and taking the move_lock in the slowpath.
+ * The RCU lock also protects the memcg from being freed when the page
+ * state that is going to change is the only thing preventing the page
+ * from being uncharged. E.g. end-writeback clearing PageWriteback(),
+ * which allows migration to go ahead and uncharge the page before the
+ * account transaction might be complete.
*/
-
-void __mem_cgroup_begin_update_page_stat(struct page *page,
- bool *locked, unsigned long *flags)
+struct mem_cgroup *mem_cgroup_begin_page_stat(struct page *page,
+ bool *locked,
+ unsigned long *flags)
{
struct mem_cgroup *memcg;
struct page_cgroup *pc;
+ rcu_read_lock();
+
+ if (mem_cgroup_disabled())
+ return NULL;
+
pc = lookup_page_cgroup(page);
again:
memcg = pc->mem_cgroup;
if (unlikely(!memcg || !PageCgroupUsed(pc)))
- return;
- /*
- * If this memory cgroup is not under account moving, we don't
- * need to take move_lock_mem_cgroup(). Because we already hold
- * rcu_read_lock(), any calls to move_account will be delayed until
- * rcu_read_unlock().
- */
- VM_BUG_ON(!rcu_read_lock_held());
+ return NULL;
+
+ *locked = false;
if (atomic_read(&memcg->moving_account) <= 0)
- return;
+ return memcg;
move_lock_mem_cgroup(memcg, flags);
if (memcg != pc->mem_cgroup || !PageCgroupUsed(pc)) {
goto again;
}
*locked = true;
+
+ return memcg;
}
-void __mem_cgroup_end_update_page_stat(struct page *page, unsigned long *flags)
+/**
+ * mem_cgroup_end_page_stat - finish a page state statistics transaction
+ * @memcg: the memcg that was accounted against
+ * @locked: value received from mem_cgroup_begin_page_stat()
+ * @flags: value received from mem_cgroup_begin_page_stat()
+ */
+void mem_cgroup_end_page_stat(struct mem_cgroup *memcg, bool locked,
+ unsigned long flags)
{
- struct page_cgroup *pc = lookup_page_cgroup(page);
+ if (memcg && locked)
+ move_unlock_mem_cgroup(memcg, &flags);
- /*
- * It's guaranteed that pc->mem_cgroup never changes while
- * lock is held because a routine modifies pc->mem_cgroup
- * should take move_lock_mem_cgroup().
- */
- move_unlock_mem_cgroup(pc->mem_cgroup, flags);
+ rcu_read_unlock();
}
-void mem_cgroup_update_page_stat(struct page *page,
+/**
+ * mem_cgroup_update_page_stat - update page state statistics
+ * @memcg: memcg to account against
+ * @idx: page state item to account
+ * @val: number of pages (positive or negative)
+ *
+ * See mem_cgroup_begin_page_stat() for locking requirements.
+ */
+void mem_cgroup_update_page_stat(struct mem_cgroup *memcg,
enum mem_cgroup_stat_index idx, int val)
{
- struct mem_cgroup *memcg;
- struct page_cgroup *pc = lookup_page_cgroup(page);
- unsigned long uninitialized_var(flags);
-
- if (mem_cgroup_disabled())
- return;
-
VM_BUG_ON(!rcu_read_lock_held());
- memcg = pc->mem_cgroup;
- if (unlikely(!memcg || !PageCgroupUsed(pc)))
- return;
- this_cpu_add(memcg->stat->count[idx], val);
+ if (memcg)
+ this_cpu_add(memcg->stat->count[idx], val);
}
/*
print_bad_pte(vma, addr, ptent, page);
if (unlikely(!__tlb_remove_page(tlb, page))) {
force_flush = 1;
+ addr += PAGE_SIZE;
break;
}
continue;
unsigned long start_pfn = pgdat->node_start_pfn;
unsigned long end_pfn = start_pfn + pgdat->node_spanned_pages;
unsigned long pfn;
- struct page *pgdat_page = virt_to_page(pgdat);
int i;
for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
node_set_offline(nid);
unregister_one_node(nid);
- if (!PageSlab(pgdat_page) && !PageCompound(pgdat_page))
- /* node data is allocated from boot memory */
- return;
-
/* free waittable in each zone */
for (i = 0; i < MAX_NR_ZONES; i++) {
struct zone *zone = pgdat->node_zones + i;
end, prev->vm_pgoff, NULL);
if (err)
return NULL;
- khugepaged_enter_vma_merge(prev);
+ khugepaged_enter_vma_merge(prev, vm_flags);
return prev;
}
next->vm_pgoff - pglen, NULL);
if (err)
return NULL;
- khugepaged_enter_vma_merge(area);
+ khugepaged_enter_vma_merge(area, vm_flags);
return area;
}
}
}
vma_unlock_anon_vma(vma);
- khugepaged_enter_vma_merge(vma);
+ khugepaged_enter_vma_merge(vma, vma->vm_flags);
validate_mm(vma->vm_mm);
return error;
}
}
}
vma_unlock_anon_vma(vma);
- khugepaged_enter_vma_merge(vma);
+ khugepaged_enter_vma_merge(vma, vma->vm_flags);
validate_mm(vma->vm_mm);
return error;
}
}
EXPORT_SYMBOL(account_page_dirtied);
-/*
- * Helper function for set_page_writeback family.
- *
- * The caller must hold mem_cgroup_begin/end_update_page_stat() lock
- * while calling this function.
- * See test_set_page_writeback for example.
- *
- * NOTE: Unlike account_page_dirtied this does not rely on being atomic
- * wrt interrupts.
- */
-void account_page_writeback(struct page *page)
-{
- mem_cgroup_inc_page_stat(page, MEM_CGROUP_STAT_WRITEBACK);
- inc_zone_page_state(page, NR_WRITEBACK);
-}
-EXPORT_SYMBOL(account_page_writeback);
-
/*
* For address_spaces which do not use buffers. Just tag the page as dirty in
* its radix tree.
int test_clear_page_writeback(struct page *page)
{
struct address_space *mapping = page_mapping(page);
- int ret;
- bool locked;
unsigned long memcg_flags;
+ struct mem_cgroup *memcg;
+ bool locked;
+ int ret;
- mem_cgroup_begin_update_page_stat(page, &locked, &memcg_flags);
+ memcg = mem_cgroup_begin_page_stat(page, &locked, &memcg_flags);
if (mapping) {
struct backing_dev_info *bdi = mapping->backing_dev_info;
unsigned long flags;
ret = TestClearPageWriteback(page);
}
if (ret) {
- mem_cgroup_dec_page_stat(page, MEM_CGROUP_STAT_WRITEBACK);
+ mem_cgroup_dec_page_stat(memcg, MEM_CGROUP_STAT_WRITEBACK);
dec_zone_page_state(page, NR_WRITEBACK);
inc_zone_page_state(page, NR_WRITTEN);
}
- mem_cgroup_end_update_page_stat(page, &locked, &memcg_flags);
+ mem_cgroup_end_page_stat(memcg, locked, memcg_flags);
return ret;
}
int __test_set_page_writeback(struct page *page, bool keep_write)
{
struct address_space *mapping = page_mapping(page);
- int ret;
- bool locked;
unsigned long memcg_flags;
+ struct mem_cgroup *memcg;
+ bool locked;
+ int ret;
- mem_cgroup_begin_update_page_stat(page, &locked, &memcg_flags);
+ memcg = mem_cgroup_begin_page_stat(page, &locked, &memcg_flags);
if (mapping) {
struct backing_dev_info *bdi = mapping->backing_dev_info;
unsigned long flags;
} else {
ret = TestSetPageWriteback(page);
}
- if (!ret)
- account_page_writeback(page);
- mem_cgroup_end_update_page_stat(page, &locked, &memcg_flags);
+ if (!ret) {
+ mem_cgroup_inc_page_stat(memcg, MEM_CGROUP_STAT_WRITEBACK);
+ inc_zone_page_state(page, NR_WRITEBACK);
+ }
+ mem_cgroup_end_page_stat(memcg, locked, memcg_flags);
return ret;
}
sizeof(struct page_cgroup) * PAGES_PER_SECTION;
BUG_ON(PageReserved(page));
+ kmemleak_free(addr);
free_pages_exact(addr, table_size);
}
}
*/
void page_add_file_rmap(struct page *page)
{
- bool locked;
+ struct mem_cgroup *memcg;
unsigned long flags;
+ bool locked;
- mem_cgroup_begin_update_page_stat(page, &locked, &flags);
+ memcg = mem_cgroup_begin_page_stat(page, &locked, &flags);
if (atomic_inc_and_test(&page->_mapcount)) {
__inc_zone_page_state(page, NR_FILE_MAPPED);
- mem_cgroup_inc_page_stat(page, MEM_CGROUP_STAT_FILE_MAPPED);
+ mem_cgroup_inc_page_stat(memcg, MEM_CGROUP_STAT_FILE_MAPPED);
}
- mem_cgroup_end_update_page_stat(page, &locked, &flags);
+ mem_cgroup_end_page_stat(memcg, locked, flags);
+}
+
+static void page_remove_file_rmap(struct page *page)
+{
+ struct mem_cgroup *memcg;
+ unsigned long flags;
+ bool locked;
+
+ memcg = mem_cgroup_begin_page_stat(page, &locked, &flags);
+
+ /* page still mapped by someone else? */
+ if (!atomic_add_negative(-1, &page->_mapcount))
+ goto out;
+
+ /* Hugepages are not counted in NR_FILE_MAPPED for now. */
+ if (unlikely(PageHuge(page)))
+ goto out;
+
+ /*
+ * We use the irq-unsafe __{inc|mod}_zone_page_stat because
+ * these counters are not modified in interrupt context, and
+ * pte lock(a spinlock) is held, which implies preemption disabled.
+ */
+ __dec_zone_page_state(page, NR_FILE_MAPPED);
+ mem_cgroup_dec_page_stat(memcg, MEM_CGROUP_STAT_FILE_MAPPED);
+
+ if (unlikely(PageMlocked(page)))
+ clear_page_mlock(page);
+out:
+ mem_cgroup_end_page_stat(memcg, locked, flags);
}
/**
*/
void page_remove_rmap(struct page *page)
{
- bool anon = PageAnon(page);
- bool locked;
- unsigned long flags;
-
- /*
- * The anon case has no mem_cgroup page_stat to update; but may
- * uncharge_page() below, where the lock ordering can deadlock if
- * we hold the lock against page_stat move: so avoid it on anon.
- */
- if (!anon)
- mem_cgroup_begin_update_page_stat(page, &locked, &flags);
+ if (!PageAnon(page)) {
+ page_remove_file_rmap(page);
+ return;
+ }
/* page still mapped by someone else? */
if (!atomic_add_negative(-1, &page->_mapcount))
- goto out;
+ return;
+
+ /* Hugepages are not counted in NR_ANON_PAGES for now. */
+ if (unlikely(PageHuge(page)))
+ return;
/*
- * Hugepages are not counted in NR_ANON_PAGES nor NR_FILE_MAPPED
- * and not charged by memcg for now.
- *
* We use the irq-unsafe __{inc|mod}_zone_page_stat because
* these counters are not modified in interrupt context, and
- * these counters are not modified in interrupt context, and
* pte lock(a spinlock) is held, which implies preemption disabled.
*/
- if (unlikely(PageHuge(page)))
- goto out;
- if (anon) {
- if (PageTransHuge(page))
- __dec_zone_page_state(page,
- NR_ANON_TRANSPARENT_HUGEPAGES);
- __mod_zone_page_state(page_zone(page), NR_ANON_PAGES,
- -hpage_nr_pages(page));
- } else {
- __dec_zone_page_state(page, NR_FILE_MAPPED);
- mem_cgroup_dec_page_stat(page, MEM_CGROUP_STAT_FILE_MAPPED);
- mem_cgroup_end_update_page_stat(page, &locked, &flags);
- }
+ if (PageTransHuge(page))
+ __dec_zone_page_state(page, NR_ANON_TRANSPARENT_HUGEPAGES);
+
+ __mod_zone_page_state(page_zone(page), NR_ANON_PAGES,
+ -hpage_nr_pages(page));
+
if (unlikely(PageMlocked(page)))
clear_page_mlock(page);
+
/*
* It would be tidy to reset the PageAnon mapping here,
* but that might overwrite a racing page_add_anon_rmap
* Leaving it set also helps swapoff to reinstate ptes
* faster for those pages still in swapcache.
*/
- return;
-out:
- if (!anon)
- mem_cgroup_end_update_page_stat(page, &locked, &flags);
}
/*
s->object_size);
continue;
}
-
-#if !defined(CONFIG_SLUB)
- if (!strcmp(s->name, name)) {
- pr_err("%s (%s): Cache name already exists.\n",
- __func__, name);
- dump_stack();
- s = NULL;
- return -EINVAL;
- }
-#endif
}
WARN_ON(strchr(name, ' ')); /* It confuses parsers */
bool "Networking support"
select NLATTR
select GENERIC_NET_UTILS
- select ANON_INODES
+ select BPF
---help---
Unless you really know what you are doing, you should say Y here.
The reason is that some programs need kernel networking support even
kfree_skb(skb);
}
+EXPORT_SYMBOL_GPL(br_deliver);
/* called with rcu_read_lock */
void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, struct sk_buff *skb0)
static int br_parse_ip_options(struct sk_buff *skb)
{
- struct ip_options *opt;
const struct iphdr *iph;
struct net_device *dev = skb->dev;
u32 len;
goto inhdr_error;
iph = ip_hdr(skb);
- opt = &(IPCB(skb)->opt);
/* Basic sanity checks */
if (iph->ihl < 5 || iph->version != 4)
}
memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
- if (iph->ihl == 5)
- return 0;
-
- opt->optlen = iph->ihl*4 - sizeof(struct iphdr);
- if (ip_options_compile(dev_net(dev), opt, skb))
- goto inhdr_error;
-
- /* Check correct handling of SRR option */
- if (unlikely(opt->srr)) {
- struct in_device *in_dev = __in_dev_get_rcu(dev);
- if (in_dev && !IN_DEV_SOURCE_ROUTE(in_dev))
- goto drop;
-
- if (ip_options_rcv_srr(skb))
- goto drop;
- }
-
+ /* We should really parse IP options here but until
+ * somebody who actually uses IP options complains to
+ * us we'll just silently ignore the options because
+ * we're lazy!
+ */
return 0;
inhdr_error:
.type = NFT_CHAIN_T_DEFAULT,
.family = NFPROTO_BRIDGE,
.owner = THIS_MODULE,
- .hook_mask = (1 << NF_BR_LOCAL_IN) |
+ .hook_mask = (1 << NF_BR_PRE_ROUTING) |
+ (1 << NF_BR_LOCAL_IN) |
(1 << NF_BR_FORWARD) |
- (1 << NF_BR_LOCAL_OUT),
+ (1 << NF_BR_LOCAL_OUT) |
+ (1 << NF_BR_POST_ROUTING),
};
static int __init nf_tables_bridge_init(void)
#include <net/netfilter/nft_reject.h>
#include <net/netfilter/ipv4/nf_reject.h>
#include <net/netfilter/ipv6/nf_reject.h>
+#include <linux/ip.h>
+#include <net/ip.h>
+#include <linux/netfilter_bridge.h>
+#include "../br_private.h"
+
+static void nft_reject_br_push_etherhdr(struct sk_buff *oldskb,
+ struct sk_buff *nskb)
+{
+ struct ethhdr *eth;
+
+ eth = (struct ethhdr *)skb_push(nskb, ETH_HLEN);
+ skb_reset_mac_header(nskb);
+ ether_addr_copy(eth->h_source, eth_hdr(oldskb)->h_dest);
+ ether_addr_copy(eth->h_dest, eth_hdr(oldskb)->h_source);
+ eth->h_proto = eth_hdr(oldskb)->h_proto;
+ skb_pull(nskb, ETH_HLEN);
+}
+
+static int nft_reject_iphdr_validate(struct sk_buff *oldskb)
+{
+ struct iphdr *iph;
+ u32 len;
+
+ if (!pskb_may_pull(oldskb, sizeof(struct iphdr)))
+ return 0;
+
+ iph = ip_hdr(oldskb);
+ if (iph->ihl < 5 || iph->version != 4)
+ return 0;
+
+ len = ntohs(iph->tot_len);
+ if (oldskb->len < len)
+ return 0;
+ else if (len < (iph->ihl*4))
+ return 0;
+
+ if (!pskb_may_pull(oldskb, iph->ihl*4))
+ return 0;
+
+ return 1;
+}
+
+static void nft_reject_br_send_v4_tcp_reset(struct sk_buff *oldskb, int hook)
+{
+ struct sk_buff *nskb;
+ struct iphdr *niph;
+ const struct tcphdr *oth;
+ struct tcphdr _oth;
+
+ if (!nft_reject_iphdr_validate(oldskb))
+ return;
+
+ oth = nf_reject_ip_tcphdr_get(oldskb, &_oth, hook);
+ if (!oth)
+ return;
+
+ nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) +
+ LL_MAX_HEADER, GFP_ATOMIC);
+ if (!nskb)
+ return;
+
+ skb_reserve(nskb, LL_MAX_HEADER);
+ niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_TCP,
+ sysctl_ip_default_ttl);
+ nf_reject_ip_tcphdr_put(nskb, oldskb, oth);
+ niph->ttl = sysctl_ip_default_ttl;
+ niph->tot_len = htons(nskb->len);
+ ip_send_check(niph);
+
+ nft_reject_br_push_etherhdr(oldskb, nskb);
+
+ br_deliver(br_port_get_rcu(oldskb->dev), nskb);
+}
+
+static void nft_reject_br_send_v4_unreach(struct sk_buff *oldskb, int hook,
+ u8 code)
+{
+ struct sk_buff *nskb;
+ struct iphdr *niph;
+ struct icmphdr *icmph;
+ unsigned int len;
+ void *payload;
+ __wsum csum;
+
+ if (!nft_reject_iphdr_validate(oldskb))
+ return;
+
+ /* IP header checks: fragment. */
+ if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET))
+ return;
+
+ /* RFC says return as much as we can without exceeding 576 bytes. */
+ len = min_t(unsigned int, 536, oldskb->len);
+
+ if (!pskb_may_pull(oldskb, len))
+ return;
+
+ if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), 0))
+ return;
+
+ nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct icmphdr) +
+ LL_MAX_HEADER + len, GFP_ATOMIC);
+ if (!nskb)
+ return;
+
+ skb_reserve(nskb, LL_MAX_HEADER);
+ niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_ICMP,
+ sysctl_ip_default_ttl);
+
+ skb_reset_transport_header(nskb);
+ icmph = (struct icmphdr *)skb_put(nskb, sizeof(struct icmphdr));
+ memset(icmph, 0, sizeof(*icmph));
+ icmph->type = ICMP_DEST_UNREACH;
+ icmph->code = code;
+
+ payload = skb_put(nskb, len);
+ memcpy(payload, skb_network_header(oldskb), len);
+
+ csum = csum_partial((void *)icmph, len + sizeof(struct icmphdr), 0);
+ icmph->checksum = csum_fold(csum);
+
+ niph->tot_len = htons(nskb->len);
+ ip_send_check(niph);
+
+ nft_reject_br_push_etherhdr(oldskb, nskb);
+
+ br_deliver(br_port_get_rcu(oldskb->dev), nskb);
+}
+
+static int nft_reject_ip6hdr_validate(struct sk_buff *oldskb)
+{
+ struct ipv6hdr *hdr;
+ u32 pkt_len;
+
+ if (!pskb_may_pull(oldskb, sizeof(struct ipv6hdr)))
+ return 0;
+
+ hdr = ipv6_hdr(oldskb);
+ if (hdr->version != 6)
+ return 0;
+
+ pkt_len = ntohs(hdr->payload_len);
+ if (pkt_len + sizeof(struct ipv6hdr) > oldskb->len)
+ return 0;
+
+ return 1;
+}
+
+static void nft_reject_br_send_v6_tcp_reset(struct net *net,
+ struct sk_buff *oldskb, int hook)
+{
+ struct sk_buff *nskb;
+ const struct tcphdr *oth;
+ struct tcphdr _oth;
+ unsigned int otcplen;
+ struct ipv6hdr *nip6h;
+
+ if (!nft_reject_ip6hdr_validate(oldskb))
+ return;
+
+ oth = nf_reject_ip6_tcphdr_get(oldskb, &_oth, &otcplen, hook);
+ if (!oth)
+ return;
+
+ nskb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(struct tcphdr) +
+ LL_MAX_HEADER, GFP_ATOMIC);
+ if (!nskb)
+ return;
+
+ skb_reserve(nskb, LL_MAX_HEADER);
+ nip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_TCP,
+ net->ipv6.devconf_all->hop_limit);
+ nf_reject_ip6_tcphdr_put(nskb, oldskb, oth, otcplen);
+ nip6h->payload_len = htons(nskb->len - sizeof(struct ipv6hdr));
+
+ nft_reject_br_push_etherhdr(oldskb, nskb);
+
+ br_deliver(br_port_get_rcu(oldskb->dev), nskb);
+}
+
+static void nft_reject_br_send_v6_unreach(struct net *net,
+ struct sk_buff *oldskb, int hook,
+ u8 code)
+{
+ struct sk_buff *nskb;
+ struct ipv6hdr *nip6h;
+ struct icmp6hdr *icmp6h;
+ unsigned int len;
+ void *payload;
+
+ if (!nft_reject_ip6hdr_validate(oldskb))
+ return;
+
+ /* Include "As much of invoking packet as possible without the ICMPv6
+ * packet exceeding the minimum IPv6 MTU" in the ICMP payload.
+ */
+ len = min_t(unsigned int, 1220, oldskb->len);
+
+ if (!pskb_may_pull(oldskb, len))
+ return;
+
+ nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct icmp6hdr) +
+ LL_MAX_HEADER + len, GFP_ATOMIC);
+ if (!nskb)
+ return;
+
+ skb_reserve(nskb, LL_MAX_HEADER);
+ nip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_ICMPV6,
+ net->ipv6.devconf_all->hop_limit);
+
+ skb_reset_transport_header(nskb);
+ icmp6h = (struct icmp6hdr *)skb_put(nskb, sizeof(struct icmp6hdr));
+ memset(icmp6h, 0, sizeof(*icmp6h));
+ icmp6h->icmp6_type = ICMPV6_DEST_UNREACH;
+ icmp6h->icmp6_code = code;
+
+ payload = skb_put(nskb, len);
+ memcpy(payload, skb_network_header(oldskb), len);
+ nip6h->payload_len = htons(nskb->len - sizeof(struct ipv6hdr));
+
+ icmp6h->icmp6_cksum =
+ csum_ipv6_magic(&nip6h->saddr, &nip6h->daddr,
+ nskb->len - sizeof(struct ipv6hdr),
+ IPPROTO_ICMPV6,
+ csum_partial(icmp6h,
+ nskb->len - sizeof(struct ipv6hdr),
+ 0));
+
+ nft_reject_br_push_etherhdr(oldskb, nskb);
+
+ br_deliver(br_port_get_rcu(oldskb->dev), nskb);
+}
static void nft_reject_bridge_eval(const struct nft_expr *expr,
struct nft_data data[NFT_REG_MAX + 1],
{
struct nft_reject *priv = nft_expr_priv(expr);
struct net *net = dev_net((pkt->in != NULL) ? pkt->in : pkt->out);
+ const unsigned char *dest = eth_hdr(pkt->skb)->h_dest;
+
+ if (is_broadcast_ether_addr(dest) ||
+ is_multicast_ether_addr(dest))
+ goto out;
switch (eth_hdr(pkt->skb)->h_proto) {
case htons(ETH_P_IP):
switch (priv->type) {
case NFT_REJECT_ICMP_UNREACH:
- nf_send_unreach(pkt->skb, priv->icmp_code);
+ nft_reject_br_send_v4_unreach(pkt->skb,
+ pkt->ops->hooknum,
+ priv->icmp_code);
break;
case NFT_REJECT_TCP_RST:
- nf_send_reset(pkt->skb, pkt->ops->hooknum);
+ nft_reject_br_send_v4_tcp_reset(pkt->skb,
+ pkt->ops->hooknum);
break;
case NFT_REJECT_ICMPX_UNREACH:
- nf_send_unreach(pkt->skb,
- nft_reject_icmp_code(priv->icmp_code));
+ nft_reject_br_send_v4_unreach(pkt->skb,
+ pkt->ops->hooknum,
+ nft_reject_icmp_code(priv->icmp_code));
break;
}
break;
case htons(ETH_P_IPV6):
switch (priv->type) {
case NFT_REJECT_ICMP_UNREACH:
- nf_send_unreach6(net, pkt->skb, priv->icmp_code,
- pkt->ops->hooknum);
+ nft_reject_br_send_v6_unreach(net, pkt->skb,
+ pkt->ops->hooknum,
+ priv->icmp_code);
break;
case NFT_REJECT_TCP_RST:
- nf_send_reset6(net, pkt->skb, pkt->ops->hooknum);
+ nft_reject_br_send_v6_tcp_reset(net, pkt->skb,
+ pkt->ops->hooknum);
break;
case NFT_REJECT_ICMPX_UNREACH:
- nf_send_unreach6(net, pkt->skb,
- nft_reject_icmpv6_code(priv->icmp_code),
- pkt->ops->hooknum);
+ nft_reject_br_send_v6_unreach(net, pkt->skb,
+ pkt->ops->hooknum,
+ nft_reject_icmpv6_code(priv->icmp_code));
break;
}
break;
/* No explicit way to reject this protocol, drop it. */
break;
}
+out:
data[NFT_REG_VERDICT].verdict = NF_DROP;
}
+static int nft_reject_bridge_validate_hooks(const struct nft_chain *chain)
+{
+ struct nft_base_chain *basechain;
+
+ if (chain->flags & NFT_BASE_CHAIN) {
+ basechain = nft_base_chain(chain);
+
+ switch (basechain->ops[0].hooknum) {
+ case NF_BR_PRE_ROUTING:
+ case NF_BR_LOCAL_IN:
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ }
+ return 0;
+}
+
static int nft_reject_bridge_init(const struct nft_ctx *ctx,
const struct nft_expr *expr,
const struct nlattr * const tb[])
{
struct nft_reject *priv = nft_expr_priv(expr);
- int icmp_code;
+ int icmp_code, err;
+
+ err = nft_reject_bridge_validate_hooks(ctx->chain);
+ if (err < 0)
+ return err;
if (tb[NFTA_REJECT_TYPE] == NULL)
return -EINVAL;
return -1;
}
+static int nft_reject_bridge_validate(const struct nft_ctx *ctx,
+ const struct nft_expr *expr,
+ const struct nft_data **data)
+{
+ return nft_reject_bridge_validate_hooks(ctx->chain);
+}
+
static struct nft_expr_type nft_reject_bridge_type;
static const struct nft_expr_ops nft_reject_bridge_ops = {
.type = &nft_reject_bridge_type,
.eval = nft_reject_bridge_eval,
.init = nft_reject_bridge_init,
.dump = nft_reject_bridge_dump,
+ .validate = nft_reject_bridge_validate,
};
static struct nft_expr_type nft_reject_bridge_type __read_mostly = {
static void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb)
{
+ if (unlikely(skb->pfmemalloc)) {
+ consume_skb(skb);
+ return;
+ }
__skb_pull(skb, skb_headlen(skb));
/* restore the reserve we had after netdev_alloc_skb_ip_align() */
skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN - skb_headroom(skb));
{
const struct ethtool_ops *ops = dev->ethtool_ops;
- if (!ops->get_eeprom || !ops->get_eeprom_len)
+ if (!ops->get_eeprom || !ops->get_eeprom_len ||
+ !ops->get_eeprom_len(dev))
return -EOPNOTSUPP;
return ethtool_get_any_eeprom(dev, useraddr, ops->get_eeprom,
u8 *data;
int ret = 0;
- if (!ops->set_eeprom || !ops->get_eeprom_len)
+ if (!ops->set_eeprom || !ops->get_eeprom_len ||
+ !ops->get_eeprom_len(dev))
return -EOPNOTSUPP;
if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
unsigned int skb_gso_transport_seglen(const struct sk_buff *skb)
{
const struct skb_shared_info *shinfo = skb_shinfo(skb);
+ unsigned int thlen = 0;
- if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))
- return tcp_hdrlen(skb) + shinfo->gso_size;
+ if (skb->encapsulation) {
+ thlen = skb_inner_transport_header(skb) -
+ skb_transport_header(skb);
+ if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))
+ thlen += inner_tcp_hdrlen(skb);
+ } else if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) {
+ thlen = tcp_hdrlen(skb);
+ }
/* UFO sets gso_size to the size of the fragmentation
* payload, i.e. the size of the L4 (UDP) header is already
* accounted for.
*/
- return shinfo->gso_size;
+ return thlen + shinfo->gso_size;
}
EXPORT_SYMBOL_GPL(skb_gso_transport_seglen);
#include <linux/export.h>
#include <net/ip.h>
#include <net/tso.h>
+#include <asm/unaligned.h>
/* Calculate expected number of TX descriptors */
int tso_count_descs(struct sk_buff *skb)
iph->id = htons(tso->ip_id);
iph->tot_len = htons(size + hdr_len - mac_hdr_len);
tcph = (struct tcphdr *)(hdr + skb_transport_offset(skb));
- tcph->seq = htonl(tso->tcp_seq);
+ put_unaligned_be32(tso->tcp_seq, &tcph->seq);
tso->ip_id++;
if (!is_last) {
dst->rcv = brcm_netdev_ops.rcv;
break;
#endif
- default:
+ case DSA_TAG_PROTO_NONE:
break;
+ default:
+ ret = -ENOPROTOOPT;
+ goto out;
}
dst->tag_protocol = drv->tag_protocol;
encap = SKB_GSO_CB(skb)->encap_level > 0;
if (encap)
- features = skb->dev->hw_enc_features & netif_skb_features(skb);
+ features &= skb->dev->hw_enc_features;
SKB_GSO_CB(skb)->encap_level += ihl;
skb_reset_transport_header(skb);
greh = (struct gre_base_hdr *)skb_transport_header(skb);
- ghl = skb_inner_network_header(skb) - skb_transport_header(skb);
+ ghl = skb_inner_mac_header(skb) - skb_transport_header(skb);
if (unlikely(ghl < sizeof(*greh)))
goto out;
skb->mac_len = skb_inner_network_offset(skb);
/* segment inner packet. */
- enc_features = skb->dev->hw_enc_features & netif_skb_features(skb);
+ enc_features = skb->dev->hw_enc_features & features;
segs = skb_mac_gso_segment(skb, enc_features);
if (IS_ERR_OR_NULL(segs)) {
skb_gso_error_unwind(skb, protocol, ghl, mac_offset, mac_len);
atomic_inc(&fq->refcnt);
spin_unlock(&hb->chain_lock);
del_timer_sync(&fq->timer);
- WARN_ON(atomic_read(&fq->refcnt) != 1);
inet_frag_put(fq, f);
goto evict_again;
}
struct inet_frag_bucket *hb;
hb = get_frag_bucket_locked(fq, f);
- hlist_del(&fq->list);
+ if (!(fq->flags & INET_FRAG_EVICTED))
+ hlist_del(&fq->list);
spin_unlock(&hb->chain_lock);
}
*/
features = netif_skb_features(skb);
segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK);
- if (IS_ERR(segs)) {
+ if (IS_ERR_OR_NULL(segs)) {
kfree_skb(skb);
return -ENOMEM;
}
* published by the Free Software Foundation.
*/
+#include <linux/module.h>
#include <net/ip.h>
#include <net/tcp.h>
#include <net/route.h>
#include <net/dst.h>
#include <linux/netfilter_ipv4.h>
+#include <net/netfilter/ipv4/nf_reject.h>
-/* Send RST reply */
-void nf_send_reset(struct sk_buff *oldskb, int hook)
+const struct tcphdr *nf_reject_ip_tcphdr_get(struct sk_buff *oldskb,
+ struct tcphdr *_oth, int hook)
{
- struct sk_buff *nskb;
- const struct iphdr *oiph;
- struct iphdr *niph;
const struct tcphdr *oth;
- struct tcphdr _otcph, *tcph;
/* IP header checks: fragment. */
if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET))
- return;
+ return NULL;
oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb),
- sizeof(_otcph), &_otcph);
+ sizeof(struct tcphdr), _oth);
if (oth == NULL)
- return;
+ return NULL;
/* No RST for RST. */
if (oth->rst)
- return;
-
- if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
- return;
+ return NULL;
/* Check checksum */
if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP))
- return;
- oiph = ip_hdr(oldskb);
+ return NULL;
- nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) +
- LL_MAX_HEADER, GFP_ATOMIC);
- if (!nskb)
- return;
+ return oth;
+}
+EXPORT_SYMBOL_GPL(nf_reject_ip_tcphdr_get);
- skb_reserve(nskb, LL_MAX_HEADER);
+struct iphdr *nf_reject_iphdr_put(struct sk_buff *nskb,
+ const struct sk_buff *oldskb,
+ __be16 protocol, int ttl)
+{
+ struct iphdr *niph, *oiph = ip_hdr(oldskb);
skb_reset_network_header(nskb);
niph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr));
niph->tos = 0;
niph->id = 0;
niph->frag_off = htons(IP_DF);
- niph->protocol = IPPROTO_TCP;
+ niph->protocol = protocol;
niph->check = 0;
niph->saddr = oiph->daddr;
niph->daddr = oiph->saddr;
+ niph->ttl = ttl;
+
+ nskb->protocol = htons(ETH_P_IP);
+
+ return niph;
+}
+EXPORT_SYMBOL_GPL(nf_reject_iphdr_put);
+
+void nf_reject_ip_tcphdr_put(struct sk_buff *nskb, const struct sk_buff *oldskb,
+ const struct tcphdr *oth)
+{
+ struct iphdr *niph = ip_hdr(nskb);
+ struct tcphdr *tcph;
skb_reset_transport_header(nskb);
tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
tcph->dest = oth->source;
tcph->doff = sizeof(struct tcphdr) / 4;
- if (oth->ack)
+ if (oth->ack) {
tcph->seq = oth->ack_seq;
- else {
+ } else {
tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin +
oldskb->len - ip_hdrlen(oldskb) -
(oth->doff << 2));
nskb->ip_summed = CHECKSUM_PARTIAL;
nskb->csum_start = (unsigned char *)tcph - nskb->head;
nskb->csum_offset = offsetof(struct tcphdr, check);
+}
+EXPORT_SYMBOL_GPL(nf_reject_ip_tcphdr_put);
+
+/* Send RST reply */
+void nf_send_reset(struct sk_buff *oldskb, int hook)
+{
+ struct sk_buff *nskb;
+ const struct iphdr *oiph;
+ struct iphdr *niph;
+ const struct tcphdr *oth;
+ struct tcphdr _oth;
+
+ oth = nf_reject_ip_tcphdr_get(oldskb, &_oth, hook);
+ if (!oth)
+ return;
+
+ if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
+ return;
+
+ oiph = ip_hdr(oldskb);
+
+ nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) +
+ LL_MAX_HEADER, GFP_ATOMIC);
+ if (!nskb)
+ return;
/* ip_route_me_harder expects skb->dst to be set */
skb_dst_set_noref(nskb, skb_dst(oldskb));
- nskb->protocol = htons(ETH_P_IP);
+ skb_reserve(nskb, LL_MAX_HEADER);
+ niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_TCP,
+ ip4_dst_hoplimit(skb_dst(nskb)));
+ nf_reject_ip_tcphdr_put(nskb, oldskb, oth);
+
if (ip_route_me_harder(nskb, RTN_UNSPEC))
goto free_nskb;
- niph->ttl = ip4_dst_hoplimit(skb_dst(nskb));
-
/* "Never happens" */
if (nskb->len > dst_mtu(skb_dst(nskb)))
goto free_nskb;
kfree_skb(nskb);
}
EXPORT_SYMBOL_GPL(nf_send_reset);
+
+MODULE_LICENSE("GPL");
.eval = nft_masq_ipv4_eval,
.init = nft_masq_init,
.dump = nft_masq_dump,
+ .validate = nft_masq_validate,
};
static struct nft_expr_type nft_masq_ipv4_type __read_mostly = {
no_route:
RT_CACHE_STAT_INC(in_no_route);
res.type = RTN_UNREACHABLE;
+ res.fi = NULL;
goto local_input;
/*
#endif
#ifdef CONFIG_TCP_MD5SIG
-static struct tcp_md5sig_pool __percpu *tcp_md5sig_pool __read_mostly;
+static DEFINE_PER_CPU(struct tcp_md5sig_pool, tcp_md5sig_pool);
static DEFINE_MUTEX(tcp_md5sig_mutex);
-
-static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool __percpu *pool)
-{
- int cpu;
-
- for_each_possible_cpu(cpu) {
- struct tcp_md5sig_pool *p = per_cpu_ptr(pool, cpu);
-
- if (p->md5_desc.tfm)
- crypto_free_hash(p->md5_desc.tfm);
- }
- free_percpu(pool);
-}
+static bool tcp_md5sig_pool_populated = false;
static void __tcp_alloc_md5sig_pool(void)
{
int cpu;
- struct tcp_md5sig_pool __percpu *pool;
-
- pool = alloc_percpu(struct tcp_md5sig_pool);
- if (!pool)
- return;
for_each_possible_cpu(cpu) {
- struct crypto_hash *hash;
-
- hash = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR_OR_NULL(hash))
- goto out_free;
+ if (!per_cpu(tcp_md5sig_pool, cpu).md5_desc.tfm) {
+ struct crypto_hash *hash;
- per_cpu_ptr(pool, cpu)->md5_desc.tfm = hash;
+ hash = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR_OR_NULL(hash))
+ return;
+ per_cpu(tcp_md5sig_pool, cpu).md5_desc.tfm = hash;
+ }
}
- /* before setting tcp_md5sig_pool, we must commit all writes
- * to memory. See ACCESS_ONCE() in tcp_get_md5sig_pool()
+ /* before setting tcp_md5sig_pool_populated, we must commit all writes
+ * to memory. See smp_rmb() in tcp_get_md5sig_pool()
*/
smp_wmb();
- tcp_md5sig_pool = pool;
- return;
-out_free:
- __tcp_free_md5sig_pool(pool);
+ tcp_md5sig_pool_populated = true;
}
bool tcp_alloc_md5sig_pool(void)
{
- if (unlikely(!tcp_md5sig_pool)) {
+ if (unlikely(!tcp_md5sig_pool_populated)) {
mutex_lock(&tcp_md5sig_mutex);
- if (!tcp_md5sig_pool)
+ if (!tcp_md5sig_pool_populated)
__tcp_alloc_md5sig_pool();
mutex_unlock(&tcp_md5sig_mutex);
}
- return tcp_md5sig_pool != NULL;
+ return tcp_md5sig_pool_populated;
}
EXPORT_SYMBOL(tcp_alloc_md5sig_pool);
*/
struct tcp_md5sig_pool *tcp_get_md5sig_pool(void)
{
- struct tcp_md5sig_pool __percpu *p;
-
local_bh_disable();
- p = ACCESS_ONCE(tcp_md5sig_pool);
- if (p)
- return raw_cpu_ptr(p);
+ if (tcp_md5sig_pool_populated) {
+ /* coupled with smp_wmb() in __tcp_alloc_md5sig_pool() */
+ smp_rmb();
+ return this_cpu_ptr(&tcp_md5sig_pool);
+ }
local_bh_enable();
return NULL;
}
inet->inet_dport = usin->sin_port;
inet->inet_daddr = daddr;
- inet_set_txhash(sk);
-
inet_csk(sk)->icsk_ext_hdr_len = 0;
if (inet_opt)
inet_csk(sk)->icsk_ext_hdr_len = inet_opt->opt.optlen;
if (err)
goto failure;
+ inet_set_txhash(sk);
+
rt = ip_route_newports(fl4, rt, orig_sport, orig_dport,
inet->inet_sport, inet->inet_dport, sk);
if (IS_ERR(rt)) {
static bool skb_still_in_host_queue(const struct sock *sk,
const struct sk_buff *skb)
{
- if (unlikely(skb_fclone_busy(skb))) {
+ if (unlikely(skb_fclone_busy(sk, skb))) {
NET_INC_STATS_BH(sock_net(sk),
LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES);
return true;
skb->encap_hdr_csum = 1;
/* segment inner packet. */
- enc_features = skb->dev->hw_enc_features & netif_skb_features(skb);
+ enc_features = skb->dev->hw_enc_features & features;
segs = gso_inner_segment(skb, enc_features);
if (IS_ERR_OR_NULL(segs)) {
skb_gso_error_unwind(skb, protocol, tnl_hlen, mac_offset,
}
write_unlock_bh(&idev->lock);
+ inet6_ifinfo_notify(RTM_NEWLINK, idev);
addrconf_verify_rtnl();
return 0;
}
encap = SKB_GSO_CB(skb)->encap_level > 0;
if (encap)
- features = skb->dev->hw_enc_features & netif_skb_features(skb);
+ features &= skb->dev->hw_enc_features;
SKB_GSO_CB(skb)->encap_level += sizeof(*ipv6h);
ipv6h = ipv6_hdr(skb);
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+
+#include <linux/module.h>
#include <net/ipv6.h>
#include <net/ip6_route.h>
#include <net/ip6_fib.h>
#include <net/ip6_checksum.h>
#include <linux/netfilter_ipv6.h>
+#include <net/netfilter/ipv6/nf_reject.h>
-void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook)
+const struct tcphdr *nf_reject_ip6_tcphdr_get(struct sk_buff *oldskb,
+ struct tcphdr *otcph,
+ unsigned int *otcplen, int hook)
{
- struct sk_buff *nskb;
- struct tcphdr otcph, *tcph;
- unsigned int otcplen, hh_len;
- int tcphoff, needs_ack;
const struct ipv6hdr *oip6h = ipv6_hdr(oldskb);
- struct ipv6hdr *ip6h;
-#define DEFAULT_TOS_VALUE 0x0U
- const __u8 tclass = DEFAULT_TOS_VALUE;
- struct dst_entry *dst = NULL;
u8 proto;
__be16 frag_off;
- struct flowi6 fl6;
-
- if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) ||
- (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) {
- pr_debug("addr is not unicast.\n");
- return;
- }
+ int tcphoff;
proto = oip6h->nexthdr;
- tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data), &proto, &frag_off);
+ tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data),
+ &proto, &frag_off);
if ((tcphoff < 0) || (tcphoff > oldskb->len)) {
pr_debug("Cannot get TCP header.\n");
- return;
+ return NULL;
}
- otcplen = oldskb->len - tcphoff;
+ *otcplen = oldskb->len - tcphoff;
/* IP header checks: fragment, too short. */
- if (proto != IPPROTO_TCP || otcplen < sizeof(struct tcphdr)) {
- pr_debug("proto(%d) != IPPROTO_TCP, "
- "or too short. otcplen = %d\n",
- proto, otcplen);
- return;
+ if (proto != IPPROTO_TCP || *otcplen < sizeof(struct tcphdr)) {
+ pr_debug("proto(%d) != IPPROTO_TCP or too short (len = %d)\n",
+ proto, *otcplen);
+ return NULL;
}
- if (skb_copy_bits(oldskb, tcphoff, &otcph, sizeof(struct tcphdr)))
- BUG();
+ otcph = skb_header_pointer(oldskb, tcphoff, sizeof(struct tcphdr),
+ otcph);
+ if (otcph == NULL)
+ return NULL;
/* No RST for RST. */
- if (otcph.rst) {
+ if (otcph->rst) {
pr_debug("RST is set\n");
- return;
+ return NULL;
}
/* Check checksum. */
if (nf_ip6_checksum(oldskb, hook, tcphoff, IPPROTO_TCP)) {
pr_debug("TCP checksum is invalid\n");
- return;
+ return NULL;
}
- memset(&fl6, 0, sizeof(fl6));
- fl6.flowi6_proto = IPPROTO_TCP;
- fl6.saddr = oip6h->daddr;
- fl6.daddr = oip6h->saddr;
- fl6.fl6_sport = otcph.dest;
- fl6.fl6_dport = otcph.source;
- security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6));
- dst = ip6_route_output(net, NULL, &fl6);
- if (dst == NULL || dst->error) {
- dst_release(dst);
- return;
- }
- dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
- if (IS_ERR(dst))
- return;
-
- hh_len = (dst->dev->hard_header_len + 15)&~15;
- nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr)
- + sizeof(struct tcphdr) + dst->trailer_len,
- GFP_ATOMIC);
-
- if (!nskb) {
- net_dbg_ratelimited("cannot alloc skb\n");
- dst_release(dst);
- return;
- }
-
- skb_dst_set(nskb, dst);
+ return otcph;
+}
+EXPORT_SYMBOL_GPL(nf_reject_ip6_tcphdr_get);
- skb_reserve(nskb, hh_len + dst->header_len);
+struct ipv6hdr *nf_reject_ip6hdr_put(struct sk_buff *nskb,
+ const struct sk_buff *oldskb,
+ __be16 protocol, int hoplimit)
+{
+ struct ipv6hdr *ip6h;
+ const struct ipv6hdr *oip6h = ipv6_hdr(oldskb);
+#define DEFAULT_TOS_VALUE 0x0U
+ const __u8 tclass = DEFAULT_TOS_VALUE;
skb_put(nskb, sizeof(struct ipv6hdr));
skb_reset_network_header(nskb);
ip6h = ipv6_hdr(nskb);
ip6_flow_hdr(ip6h, tclass, 0);
- ip6h->hop_limit = ip6_dst_hoplimit(dst);
- ip6h->nexthdr = IPPROTO_TCP;
+ ip6h->hop_limit = hoplimit;
+ ip6h->nexthdr = protocol;
ip6h->saddr = oip6h->daddr;
ip6h->daddr = oip6h->saddr;
+ nskb->protocol = htons(ETH_P_IPV6);
+
+ return ip6h;
+}
+EXPORT_SYMBOL_GPL(nf_reject_ip6hdr_put);
+
+void nf_reject_ip6_tcphdr_put(struct sk_buff *nskb,
+ const struct sk_buff *oldskb,
+ const struct tcphdr *oth, unsigned int otcplen)
+{
+ struct tcphdr *tcph;
+ int needs_ack;
+
skb_reset_transport_header(nskb);
tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
/* Truncate to length (no data) */
tcph->doff = sizeof(struct tcphdr)/4;
- tcph->source = otcph.dest;
- tcph->dest = otcph.source;
+ tcph->source = oth->dest;
+ tcph->dest = oth->source;
- if (otcph.ack) {
+ if (oth->ack) {
needs_ack = 0;
- tcph->seq = otcph.ack_seq;
+ tcph->seq = oth->ack_seq;
tcph->ack_seq = 0;
} else {
needs_ack = 1;
- tcph->ack_seq = htonl(ntohl(otcph.seq) + otcph.syn + otcph.fin
- + otcplen - (otcph.doff<<2));
+ tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin +
+ otcplen - (oth->doff<<2));
tcph->seq = 0;
}
sizeof(struct tcphdr), IPPROTO_TCP,
csum_partial(tcph,
sizeof(struct tcphdr), 0));
+}
+EXPORT_SYMBOL_GPL(nf_reject_ip6_tcphdr_put);
+
+void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook)
+{
+ struct sk_buff *nskb;
+ struct tcphdr _otcph;
+ const struct tcphdr *otcph;
+ unsigned int otcplen, hh_len;
+ const struct ipv6hdr *oip6h = ipv6_hdr(oldskb);
+ struct ipv6hdr *ip6h;
+ struct dst_entry *dst = NULL;
+ struct flowi6 fl6;
+
+ if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) ||
+ (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) {
+ pr_debug("addr is not unicast.\n");
+ return;
+ }
+
+ otcph = nf_reject_ip6_tcphdr_get(oldskb, &_otcph, &otcplen, hook);
+ if (!otcph)
+ return;
+
+ memset(&fl6, 0, sizeof(fl6));
+ fl6.flowi6_proto = IPPROTO_TCP;
+ fl6.saddr = oip6h->daddr;
+ fl6.daddr = oip6h->saddr;
+ fl6.fl6_sport = otcph->dest;
+ fl6.fl6_dport = otcph->source;
+ security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6));
+ dst = ip6_route_output(net, NULL, &fl6);
+ if (dst == NULL || dst->error) {
+ dst_release(dst);
+ return;
+ }
+ dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
+ if (IS_ERR(dst))
+ return;
+
+ hh_len = (dst->dev->hard_header_len + 15)&~15;
+ nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr)
+ + sizeof(struct tcphdr) + dst->trailer_len,
+ GFP_ATOMIC);
+
+ if (!nskb) {
+ net_dbg_ratelimited("cannot alloc skb\n");
+ dst_release(dst);
+ return;
+ }
+
+ skb_dst_set(nskb, dst);
+
+ skb_reserve(nskb, hh_len + dst->header_len);
+ ip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_TCP,
+ ip6_dst_hoplimit(dst));
+ nf_reject_ip6_tcphdr_put(nskb, oldskb, otcph, otcplen);
nf_ct_attach(nskb, oldskb);
ip6_local_out(nskb);
}
EXPORT_SYMBOL_GPL(nf_send_reset6);
+
+MODULE_LICENSE("GPL");
.eval = nft_masq_ipv6_eval,
.init = nft_masq_init,
.dump = nft_masq_dump,
+ .validate = nft_masq_validate,
};
static struct nft_expr_type nft_masq_ipv6_type __read_mostly = {
* not configured or static. These functions are needed by GSO/GRO implementation.
*/
#include <linux/export.h>
+#include <net/ip.h>
#include <net/ipv6.h>
#include <net/ip6_fib.h>
#include <net/addrconf.h>
#include <net/secure_seq.h>
+/* This function exists only for tap drivers that must support broken
+ * clients requesting UFO without specifying an IPv6 fragment ID.
+ *
+ * This is similar to ipv6_select_ident() but we use an independent hash
+ * seed to limit information leakage.
+ *
+ * The network header must be set before calling this.
+ */
+void ipv6_proxy_select_ident(struct sk_buff *skb)
+{
+ static u32 ip6_proxy_idents_hashrnd __read_mostly;
+ struct in6_addr buf[2];
+ struct in6_addr *addrs;
+ u32 hash, id;
+
+ addrs = skb_header_pointer(skb,
+ skb_network_offset(skb) +
+ offsetof(struct ipv6hdr, saddr),
+ sizeof(buf), buf);
+ if (!addrs)
+ return;
+
+ net_get_random_once(&ip6_proxy_idents_hashrnd,
+ sizeof(ip6_proxy_idents_hashrnd));
+
+ hash = __ipv6_addr_jhash(&addrs[1], ip6_proxy_idents_hashrnd);
+ hash = __ipv6_addr_jhash(&addrs[0], hash);
+
+ id = ip_idents_reserve(hash, 1);
+ skb_shinfo(skb)->ip6_frag_id = htonl(id);
+}
+EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident);
+
int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
{
u16 offset = sizeof(struct ipv6hdr);
sk->sk_v6_daddr = usin->sin6_addr;
np->flow_label = fl6.flowlabel;
- ip6_set_txhash(sk);
-
/*
* TCP over IPv4
*/
if (err)
goto late_failure;
+ ip6_set_txhash(sk);
+
if (!tp->write_seq && likely(!tp->repair))
tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
sk->sk_v6_daddr.s6_addr32,
case IPPROTO_DCCP:
if (!onlyproto && (nh + offset + 4 < skb->data ||
pskb_may_pull(skb, nh + offset + 4 - skb->data))) {
- __be16 *ports = (__be16 *)exthdr;
+ __be16 *ports;
+ nh = skb_network_header(skb);
+ ports = (__be16 *)(nh + offset);
fl6->fl6_sport = ports[!!reverse];
fl6->fl6_dport = ports[!reverse];
}
case IPPROTO_ICMPV6:
if (!onlyproto && pskb_may_pull(skb, nh + offset + 2 - skb->data)) {
- u8 *icmp = (u8 *)exthdr;
+ u8 *icmp;
+ nh = skb_network_header(skb);
+ icmp = (u8 *)(nh + offset);
fl6->fl6_icmp_type = icmp[0];
fl6->fl6_icmp_code = icmp[1];
}
case IPPROTO_MH:
if (!onlyproto && pskb_may_pull(skb, nh + offset + 3 - skb->data)) {
struct ip6_mh *mh;
- mh = (struct ip6_mh *)exthdr;
+ nh = skb_network_header(skb);
+ mh = (struct ip6_mh *)(nh + offset);
fl6->fl6_mh_type = mh->ip6mh_type;
}
fl6->flowi6_proto = nexthdr;
if (sk->sk_state != TCP_ESTABLISHED) {
sock->state = SS_UNCONNECTED;
- if (sk->sk_prot->disconnect(sk, flags))
- sock->state = SS_DISCONNECTING;
err = sock_error(sk);
if (!err)
err = -ECONNRESET;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (chanctx_conf) {
- *chandef = chanctx_conf->def;
+ *chandef = sdata->vif.bss_conf.chandef;
ret = 0;
} else if (local->open_count > 0 &&
local->open_count == local->monitors &&
*/
if (!(rates[0].flags & IEEE80211_TX_RC_MCS)) {
u32 basic_rates = vif->bss_conf.basic_rates;
- s8 baserate = basic_rates ? ffs(basic_rates - 1) : 0;
+ s8 baserate = basic_rates ? ffs(basic_rates) - 1 : 0;
rate = &sband->bitrates[rates[0].idx];
unsigned int i, tp, prob, eprob;
char *p;
- ms = kmalloc(sizeof(*ms) + 4096, GFP_KERNEL);
+ ms = kmalloc(2048, GFP_KERNEL);
if (!ms)
return -ENOMEM;
file->private_data = ms;
p = ms->buf;
- p += sprintf(p, "rate throughput ewma prob this prob "
- "this succ/attempt success attempts\n");
+ p += sprintf(p, "rate tpt eprob *prob"
+ " *ok(*cum) ok( cum)\n");
for (i = 0; i < mi->n_rates; i++) {
struct minstrel_rate *mr = &mi->r[i];
struct minstrel_rate_stats *mrs = &mi->r[i].stats;
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
eprob = MINSTREL_TRUNC(mrs->probability * 1000);
- p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u "
- " %3u(%3u) %8llu %8llu\n",
+ p += sprintf(p, " %4u.%1u %3u.%1u %3u.%1u"
+ " %4u(%4u) %9llu(%9llu)\n",
tp / 10, tp % 10,
eprob / 10, eprob % 10,
prob / 10, prob % 10,
mi->sample_packets);
ms->len = p - ms->buf;
+ WARN_ON(ms->len + sizeof(*ms) > 2048);
+
return 0;
}
prob = MINSTREL_TRUNC(mr->cur_prob * 1000);
eprob = MINSTREL_TRUNC(mr->probability * 1000);
- p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u "
- "%3u %3u(%3u) %8llu %8llu\n",
+ p += sprintf(p, " %4u.%1u %3u.%1u %3u.%1u "
+ "%3u %4u(%4u) %9llu(%9llu)\n",
tp / 10, tp % 10,
eprob / 10, eprob % 10,
prob / 10, prob % 10,
return ret;
}
- ms = kmalloc(sizeof(*ms) + 8192, GFP_KERNEL);
+ ms = kmalloc(8192, GFP_KERNEL);
if (!ms)
return -ENOMEM;
file->private_data = ms;
p = ms->buf;
- p += sprintf(p, "type rate throughput ewma prob "
- "this prob retry this succ/attempt success attempts\n");
+ p += sprintf(p, "type rate tpt eprob *prob "
+ "ret *ok(*cum) ok( cum)\n");
+
p = minstrel_ht_stats_dump(mi, max_mcs, p);
for (i = 0; i < max_mcs; i++)
MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10);
ms->len = p - ms->buf;
+ WARN_ON(ms->len + sizeof(*ms) > 8192);
+
return nonseekable_open(inode, file);
}
* @known_smps_mode: the smps_mode the client thinks we are in. Relevant for
* AP only.
* @cipher_scheme: optional cipher scheme for this station
+ * @last_tdls_pkt_time: holds the time in jiffies of last TDLS pkt ACKed
*/
struct sta_info {
/* General information, mostly static */
#
# Makefile for MPLS.
#
-obj-y += mpls_gso.o
+obj-$(CONFIG_NET_MPLS_GSO) += mpls_gso.o
__skb_push(skb, skb->mac_len);
/* Segment inner packet. */
- mpls_features = skb->dev->mpls_features & netif_skb_features(skb);
+ mpls_features = skb->dev->mpls_features & features;
segs = skb_mac_gso_segment(skb, mpls_features);
* above pulled. It will be re-pushed after returning
* skb_mac_gso_segment(), an indirect caller of this function.
*/
- __skb_push(skb, skb->data - skb_mac_header(skb));
-
+ __skb_pull(skb, skb->data - skb_mac_header(skb));
out:
return segs;
}
struct ip_set *set;
struct ip_set_net *inst = ip_set_pernet(net);
- if (index > inst->ip_set_max)
+ if (index >= inst->ip_set_max)
return IPSET_INVALID_ID;
nfnl_lock(NFNL_SUBSYS_IPSET);
if (unlikely(crosses_local_route_boundary(skb_af, skb, rt_mode,
local))) {
IP_VS_DBG_RL("We are crossing local and non-local addresses"
- " daddr=%pI4\n", &dest->addr.ip);
+ " daddr=%pI4\n", &daddr);
goto err_put;
}
if (unlikely(crosses_local_route_boundary(skb_af, skb, rt_mode,
local))) {
IP_VS_DBG_RL("We are crossing local and non-local addresses"
- " daddr=%pI6\n", &dest->addr.in6);
+ " daddr=%pI6\n", daddr);
goto err_put;
}
{
/* REPLY */
/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */
-/*syn*/ { sIV, sS2, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sS2 },
+/*syn*/ { sIV, sS2, sIV, sIV, sIV, sIV, sIV, sSS, sIV, sS2 },
/*
* sNO -> sIV Never reached.
* sSS -> sS2 Simultaneous open
* sFW -> sIV
* sCW -> sIV
* sLA -> sIV
- * sTW -> sIV Reopened connection, but server may not do it.
+ * sTW -> sSS Reopened connection, but server may have switched role
* sCL -> sIV
*/
/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */
basechain->stats = stats;
} else {
stats = netdev_alloc_pcpu_stats(struct nft_stats);
- if (IS_ERR(stats)) {
+ if (stats == NULL) {
module_put(type->owner);
kfree(basechain);
- return PTR_ERR(stats);
+ return -ENOMEM;
}
rcu_assign_pointer(basechain->stats, stats);
}
.abort = nf_tables_abort,
};
+int nft_chain_validate_dependency(const struct nft_chain *chain,
+ enum nft_chain_type type)
+{
+ const struct nft_base_chain *basechain;
+
+ if (chain->flags & NFT_BASE_CHAIN) {
+ basechain = nft_base_chain(chain);
+ if (basechain->type->type != type)
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nft_chain_validate_dependency);
+
/*
* Loop detection - walk through the ruleset beginning at the destination chain
* of a new jump until either the source chain is reached (loop) or all
#define NFULNL_NLBUFSIZ_DEFAULT NLMSG_GOODSIZE
#define NFULNL_TIMEOUT_DEFAULT 100 /* every second */
#define NFULNL_QTHRESH_DEFAULT 100 /* 100 packets */
-#define NFULNL_COPY_RANGE_MAX 0xFFFF /* max packet size is limited by 16-bit struct nfattr nfa_len field */
+/* max packet size is limited by 16-bit struct nfattr nfa_len field */
+#define NFULNL_COPY_RANGE_MAX (0xFFFF - NLA_HDRLEN)
#define PRINTR(x, args...) do { if (net_ratelimit()) \
printk(x, ## args); } while (0);
case NFULNL_COPY_PACKET:
inst->copy_mode = mode;
+ if (range == 0)
+ range = NFULNL_COPY_RANGE_MAX;
inst->copy_range = min_t(unsigned int,
range, NFULNL_COPY_RANGE_MAX);
break;
return skb;
}
-static int
+static void
__nfulnl_send(struct nfulnl_instance *inst)
{
- int status = -1;
-
if (inst->qlen > 1) {
struct nlmsghdr *nlh = nlmsg_put(inst->skb, 0, 0,
NLMSG_DONE,
sizeof(struct nfgenmsg),
0);
- if (!nlh)
+ if (WARN_ONCE(!nlh, "bad nlskb size: %u, tailroom %d\n",
+ inst->skb->len, skb_tailroom(inst->skb))) {
+ kfree_skb(inst->skb);
goto out;
+ }
}
- status = nfnetlink_unicast(inst->skb, inst->net, inst->peer_portid,
- MSG_DONTWAIT);
-
+ nfnetlink_unicast(inst->skb, inst->net, inst->peer_portid,
+ MSG_DONTWAIT);
+out:
inst->qlen = 0;
inst->skb = NULL;
-out:
- return status;
}
static void
+ nla_total_size(sizeof(u_int32_t)) /* gid */
+ nla_total_size(plen) /* prefix */
+ nla_total_size(sizeof(struct nfulnl_msg_packet_hw))
- + nla_total_size(sizeof(struct nfulnl_msg_packet_timestamp));
+ + nla_total_size(sizeof(struct nfulnl_msg_packet_timestamp))
+ + nla_total_size(sizeof(struct nfgenmsg)); /* NLMSG_DONE */
if (in && skb_mac_header_was_set(skb)) {
size += nla_total_size(skb->dev->hard_header_len)
break;
case NFULNL_COPY_PACKET:
- if (inst->copy_range == 0
- || inst->copy_range > skb->len)
+ if (inst->copy_range > skb->len)
data_len = skb->len;
else
data_len = inst->copy_range;
goto unlock_and_release;
}
- if (inst->skb &&
- size > skb_tailroom(inst->skb) - sizeof(struct nfgenmsg)) {
+ if (inst->skb && size > skb_tailroom(inst->skb)) {
/* either the queue len is too high or we don't have
* enough room in the skb left. flush to userspace. */
__nfulnl_flush(inst);
* returned by nf_queue. For instance, callers rely on -ECANCELED to
* mean 'ignore this hook'.
*/
- if (IS_ERR(segs))
+ if (IS_ERR_OR_NULL(segs))
goto out_err;
queued = 0;
err = 0;
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
-#include <asm/uaccess.h> /* for set_fs */
#include <net/netfilter/nf_tables.h>
+static const struct {
+ const char *name;
+ u8 type;
+} table_to_chaintype[] = {
+ { "filter", NFT_CHAIN_T_DEFAULT },
+ { "raw", NFT_CHAIN_T_DEFAULT },
+ { "security", NFT_CHAIN_T_DEFAULT },
+ { "mangle", NFT_CHAIN_T_ROUTE },
+ { "nat", NFT_CHAIN_T_NAT },
+ { },
+};
+
+static int nft_compat_table_to_chaintype(const char *table)
+{
+ int i;
+
+ for (i = 0; table_to_chaintype[i].name != NULL; i++) {
+ if (strcmp(table_to_chaintype[i].name, table) == 0)
+ return table_to_chaintype[i].type;
+ }
+
+ return -1;
+}
+
+static int nft_compat_chain_validate_dependency(const char *tablename,
+ const struct nft_chain *chain)
+{
+ enum nft_chain_type type;
+ const struct nft_base_chain *basechain;
+
+ if (!tablename || !(chain->flags & NFT_BASE_CHAIN))
+ return 0;
+
+ type = nft_compat_table_to_chaintype(tablename);
+ if (type < 0)
+ return -EINVAL;
+
+ basechain = nft_base_chain(chain);
+ if (basechain->type->type != type)
+ return -EINVAL;
+
+ return 0;
+}
+
union nft_entry {
struct ipt_entry e4;
struct ip6t_entry e6;
const struct nf_hook_ops *ops = &basechain->ops[0];
par->hook_mask = 1 << ops->hooknum;
+ } else {
+ par->hook_mask = 0;
}
par->family = ctx->afi->family;
}
union nft_entry e = {};
int ret;
+ ret = nft_compat_chain_validate_dependency(target->table, ctx->chain);
+ if (ret < 0)
+ goto err;
+
target_compat_from_user(target, nla_data(tb[NFTA_TARGET_INFO]), info);
if (ctx->nla[NFTA_RULE_COMPAT]) {
{
struct xt_target *target = expr->ops->data;
unsigned int hook_mask = 0;
+ int ret;
if (ctx->chain->flags & NFT_BASE_CHAIN) {
const struct nft_base_chain *basechain =
const struct nf_hook_ops *ops = &basechain->ops[0];
hook_mask = 1 << ops->hooknum;
- if (hook_mask & target->hooks)
- return 0;
+ if (!(hook_mask & target->hooks))
+ return -EINVAL;
- /* This target is being called from an invalid chain */
- return -EINVAL;
+ ret = nft_compat_chain_validate_dependency(target->table,
+ ctx->chain);
+ if (ret < 0)
+ return ret;
}
return 0;
}
const struct nf_hook_ops *ops = &basechain->ops[0];
par->hook_mask = 1 << ops->hooknum;
+ } else {
+ par->hook_mask = 0;
}
par->family = ctx->afi->family;
}
union nft_entry e = {};
int ret;
+ ret = nft_compat_chain_validate_dependency(match->name, ctx->chain);
+ if (ret < 0)
+ goto err;
+
match_compat_from_user(match, nla_data(tb[NFTA_MATCH_INFO]), info);
if (ctx->nla[NFTA_RULE_COMPAT]) {
{
struct xt_match *match = expr->ops->data;
unsigned int hook_mask = 0;
+ int ret;
if (ctx->chain->flags & NFT_BASE_CHAIN) {
const struct nft_base_chain *basechain =
const struct nf_hook_ops *ops = &basechain->ops[0];
hook_mask = 1 << ops->hooknum;
- if (hook_mask & match->hooks)
- return 0;
+ if (!(hook_mask & match->hooks))
+ return -EINVAL;
- /* This match is being called from an invalid chain */
- return -EINVAL;
+ ret = nft_compat_chain_validate_dependency(match->name,
+ ctx->chain);
+ if (ret < 0)
+ return ret;
}
return 0;
}
family = ctx->afi->family;
/* Re-use the existing target if it's already loaded. */
- list_for_each_entry(nft_target, &nft_match_list, head) {
+ list_for_each_entry(nft_target, &nft_target_list, head) {
struct xt_target *target = nft_target->ops.data;
if (strcmp(target->name, tg_name) == 0 &&
const struct nlattr * const tb[])
{
struct nft_masq *priv = nft_expr_priv(expr);
+ int err;
+
+ err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
+ if (err < 0)
+ return err;
if (tb[NFTA_MASQ_FLAGS] == NULL)
return 0;
}
EXPORT_SYMBOL_GPL(nft_masq_dump);
+int nft_masq_validate(const struct nft_ctx *ctx, const struct nft_expr *expr,
+ const struct nft_data **data)
+{
+ return nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
+}
+EXPORT_SYMBOL_GPL(nft_masq_validate);
+
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>");
u32 family;
int err;
- if (tb[NFTA_NAT_TYPE] == NULL)
+ err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
+ if (err < 0)
+ return err;
+
+ if (tb[NFTA_NAT_TYPE] == NULL ||
+ (tb[NFTA_NAT_REG_ADDR_MIN] == NULL &&
+ tb[NFTA_NAT_REG_PROTO_MIN] == NULL))
return -EINVAL;
switch (ntohl(nla_get_be32(tb[NFTA_NAT_TYPE]))) {
priv->family = family;
if (tb[NFTA_NAT_REG_ADDR_MIN]) {
- priv->sreg_addr_min = ntohl(nla_get_be32(
- tb[NFTA_NAT_REG_ADDR_MIN]));
+ priv->sreg_addr_min =
+ ntohl(nla_get_be32(tb[NFTA_NAT_REG_ADDR_MIN]));
+
err = nft_validate_input_register(priv->sreg_addr_min);
if (err < 0)
return err;
- }
- if (tb[NFTA_NAT_REG_ADDR_MAX]) {
- priv->sreg_addr_max = ntohl(nla_get_be32(
- tb[NFTA_NAT_REG_ADDR_MAX]));
- err = nft_validate_input_register(priv->sreg_addr_max);
- if (err < 0)
- return err;
- } else
- priv->sreg_addr_max = priv->sreg_addr_min;
+ if (tb[NFTA_NAT_REG_ADDR_MAX]) {
+ priv->sreg_addr_max =
+ ntohl(nla_get_be32(tb[NFTA_NAT_REG_ADDR_MAX]));
+
+ err = nft_validate_input_register(priv->sreg_addr_max);
+ if (err < 0)
+ return err;
+ } else {
+ priv->sreg_addr_max = priv->sreg_addr_min;
+ }
+ }
if (tb[NFTA_NAT_REG_PROTO_MIN]) {
- priv->sreg_proto_min = ntohl(nla_get_be32(
- tb[NFTA_NAT_REG_PROTO_MIN]));
+ priv->sreg_proto_min =
+ ntohl(nla_get_be32(tb[NFTA_NAT_REG_PROTO_MIN]));
+
err = nft_validate_input_register(priv->sreg_proto_min);
if (err < 0)
return err;
- }
- if (tb[NFTA_NAT_REG_PROTO_MAX]) {
- priv->sreg_proto_max = ntohl(nla_get_be32(
- tb[NFTA_NAT_REG_PROTO_MAX]));
- err = nft_validate_input_register(priv->sreg_proto_max);
- if (err < 0)
- return err;
- } else
- priv->sreg_proto_max = priv->sreg_proto_min;
+ if (tb[NFTA_NAT_REG_PROTO_MAX]) {
+ priv->sreg_proto_max =
+ ntohl(nla_get_be32(tb[NFTA_NAT_REG_PROTO_MAX]));
+
+ err = nft_validate_input_register(priv->sreg_proto_max);
+ if (err < 0)
+ return err;
+ } else {
+ priv->sreg_proto_max = priv->sreg_proto_min;
+ }
+ }
if (tb[NFTA_NAT_FLAGS]) {
priv->flags = ntohl(nla_get_be32(tb[NFTA_NAT_FLAGS]));
if (nla_put_be32(skb, NFTA_NAT_FAMILY, htonl(priv->family)))
goto nla_put_failure;
- if (nla_put_be32(skb,
- NFTA_NAT_REG_ADDR_MIN, htonl(priv->sreg_addr_min)))
- goto nla_put_failure;
- if (nla_put_be32(skb,
- NFTA_NAT_REG_ADDR_MAX, htonl(priv->sreg_addr_max)))
- goto nla_put_failure;
+
+ if (priv->sreg_addr_min) {
+ if (nla_put_be32(skb, NFTA_NAT_REG_ADDR_MIN,
+ htonl(priv->sreg_addr_min)) ||
+ nla_put_be32(skb, NFTA_NAT_REG_ADDR_MAX,
+ htonl(priv->sreg_addr_max)))
+ goto nla_put_failure;
+ }
+
if (priv->sreg_proto_min) {
if (nla_put_be32(skb, NFTA_NAT_REG_PROTO_MIN,
- htonl(priv->sreg_proto_min)))
- goto nla_put_failure;
- if (nla_put_be32(skb, NFTA_NAT_REG_PROTO_MAX,
+ htonl(priv->sreg_proto_min)) ||
+ nla_put_be32(skb, NFTA_NAT_REG_PROTO_MAX,
htonl(priv->sreg_proto_max)))
goto nla_put_failure;
}
return -1;
}
+static int nft_nat_validate(const struct nft_ctx *ctx,
+ const struct nft_expr *expr,
+ const struct nft_data **data)
+{
+ return nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
+}
+
static struct nft_expr_type nft_nat_type;
static const struct nft_expr_ops nft_nat_ops = {
.type = &nft_nat_type,
.eval = nft_nat_eval,
.init = nft_nat_init,
.dump = nft_nat_dump,
+ .validate = nft_nat_validate,
};
static struct nft_expr_type nft_nat_type __read_mostly = {
static int netlink_dump(struct sock *sk);
static void netlink_skb_destructor(struct sk_buff *skb);
+/* nl_table locking explained:
+ * Lookup and traversal are protected with nl_sk_hash_lock or nl_table_lock
+ * combined with an RCU read-side lock. Insertion and removal are protected
+ * with nl_sk_hash_lock while using RCU list modification primitives and may
+ * run in parallel to nl_table_lock protected lookups. Destruction of the
+ * Netlink socket may only occur *after* nl_table_lock has been acquired
+ * either during or after the socket has been removed from the list.
+ */
DEFINE_RWLOCK(nl_table_lock);
EXPORT_SYMBOL_GPL(nl_table_lock);
static atomic_t nl_table_users = ATOMIC_INIT(0);
static int lockdep_nl_sk_hash_is_held(void)
{
#ifdef CONFIG_LOCKDEP
- return (debug_locks) ? lockdep_is_held(&nl_sk_hash_lock) : 1;
-#else
- return 1;
+ if (debug_locks)
+ return lockdep_is_held(&nl_sk_hash_lock) || lockdep_is_held(&nl_table_lock);
#endif
+ return 1;
}
static ATOMIC_NOTIFIER_HEAD(netlink_chain);
struct netlink_table *table = &nl_table[protocol];
struct sock *sk;
+ read_lock(&nl_table_lock);
rcu_read_lock();
sk = __netlink_lookup(table, portid, net);
if (sk)
sock_hold(sk);
rcu_read_unlock();
+ read_unlock(&nl_table_lock);
return sk;
}
}
netlink_table_ungrab();
- /* Wait for readers to complete */
- synchronize_net();
-
kfree(nlk->groups);
nlk->groups = NULL;
retry:
cond_resched();
+ netlink_table_grab();
rcu_read_lock();
if (__netlink_lookup(table, portid, net)) {
/* Bind collision, search negative portid values. */
if (rover > -4097)
rover = -4097;
rcu_read_unlock();
+ netlink_table_ungrab();
goto retry;
}
rcu_read_unlock();
+ netlink_table_ungrab();
err = netlink_insert(sk, net, portid);
if (err == -EADDRINUSE)
}
static void *netlink_seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(RCU)
+ __acquires(nl_table_lock) __acquires(RCU)
{
+ read_lock(&nl_table_lock);
rcu_read_lock();
return *pos ? netlink_seq_socket_idx(seq, *pos - 1) : SEQ_START_TOKEN;
}
static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
+ struct rhashtable *ht;
struct netlink_sock *nlk;
struct nl_seq_iter *iter;
struct net *net;
iter = seq->private;
nlk = v;
- rht_for_each_entry_rcu(nlk, nlk->node.next, node)
+ i = iter->link;
+ ht = &nl_table[i].hash;
+ rht_for_each_entry(nlk, nlk->node.next, ht, node)
if (net_eq(sock_net((struct sock *)nlk), net))
return nlk;
- i = iter->link;
j = iter->hash_idx + 1;
do {
- struct rhashtable *ht = &nl_table[i].hash;
const struct bucket_table *tbl = rht_dereference_rcu(ht->tbl, ht);
for (; j < tbl->size; j++) {
- rht_for_each_entry_rcu(nlk, tbl->buckets[j], node) {
+ rht_for_each_entry(nlk, tbl->buckets[j], ht, node) {
if (net_eq(sock_net((struct sock *)nlk), net)) {
iter->link = i;
iter->hash_idx = j;
}
static void netlink_seq_stop(struct seq_file *seq, void *v)
- __releases(RCU)
+ __releases(RCU) __releases(nl_table_lock)
{
rcu_read_unlock();
+ read_unlock(&nl_table_lock);
}
segs = __skb_gso_segment(skb, NETIF_F_SG, false);
if (IS_ERR(segs))
return PTR_ERR(segs);
+ if (segs == NULL)
+ return -EINVAL;
/* Queue all of the segments. */
skb = segs;
if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS])) == 0) {
if (qdisc_is_percpu_stats(sch)) {
sch->cpu_bstats =
- alloc_percpu(struct gnet_stats_basic_cpu);
+ netdev_alloc_pcpu_stats(struct gnet_stats_basic_cpu);
if (!sch->cpu_bstats)
goto err_out4;
sch->limit = q->params.limit;
setup_timer(&q->adapt_timer, pie_timer, (unsigned long)sch);
- mod_timer(&q->adapt_timer, jiffies + HZ / 2);
if (opt) {
int err = pie_change(sch, opt);
return err;
}
+ mod_timer(&q->adapt_timer, jiffies + HZ / 2);
return 0;
}
void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
{
struct tipc_link **active = &n_ptr->active_links[0];
- u32 addr = n_ptr->addr;
n_ptr->working_links++;
- tipc_nametbl_publish(TIPC_LINK_STATE, addr, addr, TIPC_NODE_SCOPE,
- l_ptr->bearer_id, addr);
+ n_ptr->action_flags |= TIPC_NOTIFY_LINK_UP;
+ n_ptr->link_id = l_ptr->peer_bearer_id << 16 | l_ptr->bearer_id;
+
pr_info("Established link <%s> on network plane %c\n",
l_ptr->name, l_ptr->net_plane);
void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
{
struct tipc_link **active;
- u32 addr = n_ptr->addr;
n_ptr->working_links--;
- tipc_nametbl_withdraw(TIPC_LINK_STATE, addr, l_ptr->bearer_id, addr);
+ n_ptr->action_flags |= TIPC_NOTIFY_LINK_DOWN;
+ n_ptr->link_id = l_ptr->peer_bearer_id << 16 | l_ptr->bearer_id;
if (!tipc_link_is_active(l_ptr)) {
pr_info("Lost standby link <%s> on network plane %c\n",
LIST_HEAD(conn_sks);
struct sk_buff_head waiting_sks;
u32 addr = 0;
- unsigned int flags = node->action_flags;
+ int flags = node->action_flags;
+ u32 link_id = 0;
- if (likely(!node->action_flags)) {
+ if (likely(!flags)) {
spin_unlock_bh(&node->lock);
return;
}
+ addr = node->addr;
+ link_id = node->link_id;
__skb_queue_head_init(&waiting_sks);
- if (node->action_flags & TIPC_WAKEUP_USERS) {
+
+ if (flags & TIPC_WAKEUP_USERS)
skb_queue_splice_init(&node->waiting_sks, &waiting_sks);
- node->action_flags &= ~TIPC_WAKEUP_USERS;
- }
- if (node->action_flags & TIPC_NOTIFY_NODE_DOWN) {
+
+ if (flags & TIPC_NOTIFY_NODE_DOWN) {
list_replace_init(&node->nsub, &nsub_list);
list_replace_init(&node->conn_sks, &conn_sks);
- node->action_flags &= ~TIPC_NOTIFY_NODE_DOWN;
}
- if (node->action_flags & TIPC_NOTIFY_NODE_UP) {
- node->action_flags &= ~TIPC_NOTIFY_NODE_UP;
- addr = node->addr;
- }
- node->action_flags &= ~TIPC_WAKEUP_BCAST_USERS;
+ node->action_flags &= ~(TIPC_WAKEUP_USERS | TIPC_NOTIFY_NODE_DOWN |
+ TIPC_NOTIFY_NODE_UP | TIPC_NOTIFY_LINK_UP |
+ TIPC_NOTIFY_LINK_DOWN |
+ TIPC_WAKEUP_BCAST_USERS);
+
spin_unlock_bh(&node->lock);
while (!skb_queue_empty(&waiting_sks))
if (flags & TIPC_WAKEUP_BCAST_USERS)
tipc_bclink_wakeup_users();
- if (addr)
+ if (flags & TIPC_NOTIFY_NODE_UP)
tipc_named_node_up(addr);
+
+ if (flags & TIPC_NOTIFY_LINK_UP)
+ tipc_nametbl_publish(TIPC_LINK_STATE, addr, addr,
+ TIPC_NODE_SCOPE, link_id, addr);
+
+ if (flags & TIPC_NOTIFY_LINK_DOWN)
+ tipc_nametbl_withdraw(TIPC_LINK_STATE, addr,
+ link_id, addr);
}
* TIPC_WAIT_OWN_LINKS_DOWN: wait until peer node is declared down
* TIPC_NOTIFY_NODE_DOWN: notify node is down
* TIPC_NOTIFY_NODE_UP: notify node is up
+ * TIPC_DISTRIBUTE_NAME: publish or withdraw link state name type
*/
enum {
TIPC_WAIT_PEER_LINKS_DOWN = (1 << 1),
TIPC_NOTIFY_NODE_DOWN = (1 << 3),
TIPC_NOTIFY_NODE_UP = (1 << 4),
TIPC_WAKEUP_USERS = (1 << 5),
- TIPC_WAKEUP_BCAST_USERS = (1 << 6)
+ TIPC_WAKEUP_BCAST_USERS = (1 << 6),
+ TIPC_NOTIFY_LINK_UP = (1 << 7),
+ TIPC_NOTIFY_LINK_DOWN = (1 << 8)
};
/**
* @working_links: number of working links to node (both active and standby)
* @link_cnt: number of links to node
* @signature: node instance identifier
+ * @link_id: local and remote bearer ids of changing link, if any
* @nsub: list of "node down" subscriptions monitoring node
* @rcu: rcu struct for tipc_node
*/
int link_cnt;
int working_links;
u32 signature;
+ u32 link_id;
struct list_head nsub;
struct sk_buff_head waiting_sks;
struct list_head conn_sks;
sk = &tsk->sk;
/* Queue message */
- bh_lock_sock(sk);
+ spin_lock_bh(&sk->sk_lock.slock);
if (!sock_owned_by_user(sk)) {
rc = filter_rcv(sk, buf);
if (sk_add_backlog(sk, buf, limit))
rc = -TIPC_ERR_OVERLOAD;
}
- bh_unlock_sock(sk);
+ spin_unlock_bh(&sk->sk_lock.slock);
tipc_sk_put(tsk);
if (likely(!rc))
return 0;
case SIOCGETLINKNAME:
if (copy_from_user(&lnr, argp, sizeof(lnr)))
return -EFAULT;
- if (!tipc_node_get_linkname(lnr.bearer_id, lnr.peer,
+ if (!tipc_node_get_linkname(lnr.bearer_id & 0xffff, lnr.peer,
lnr.linkname, TIPC_MAX_LINK_NAME)) {
if (copy_to_user(argp, &lnr, sizeof(lnr)))
return -EFAULT;
int err;
bool need_new_beacon = false;
int len, i;
+ u32 cs_count;
if (!rdev->ops->channel_switch ||
!(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH))
if (need_new_beacon && !info->attrs[NL80211_ATTR_CSA_IES])
return -EINVAL;
- params.count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]);
+ /* Even though the attribute is u32, the specification says
+ * u8, so let's make sure we don't overflow.
+ */
+ cs_count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]);
+ if (cs_count > 255)
+ return -EINVAL;
+
+ params.count = cs_count;
if (!need_new_beacon)
goto skip_beacons;
kfree_skb(skb);
if (IS_ERR(segs))
return PTR_ERR(segs);
+ if (segs == NULL)
+ return -EINVAL;
do {
struct sk_buff *nskb = segs->next;
struct xfrm_policy *pol = xdst->pols[0];
struct xfrm_policy_queue *pq = &pol->polq;
- if (unlikely(skb_fclone_busy(skb))) {
+ if (unlikely(skb_fclone_busy(sk, skb))) {
kfree_skb(skb);
return 0;
}
.errstr = "R0 !read_ok",
.result = REJECT,
},
+ {
+ "program doesn't init R0 before exit in all branches",
+ .insns = {
+ BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2),
+ BPF_MOV64_IMM(BPF_REG_0, 1),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 2),
+ BPF_EXIT_INSN(),
+ },
+ .errstr = "R0 !read_ok",
+ .result = REJECT,
+ },
{
"stack out of bounds",
.insns = {
{
const struct evm_ima_xattr_data *xattr_data = xattr_value;
- if ((strcmp(xattr_name, XATTR_NAME_EVM) == 0)
- && (xattr_data->type == EVM_XATTR_HMAC))
- return -EPERM;
+ if (strcmp(xattr_name, XATTR_NAME_EVM) == 0) {
+ if (!xattr_value_len)
+ return -EINVAL;
+ if (xattr_data->type != EVM_IMA_XATTR_DIGSIG)
+ return -EPERM;
+ }
return evm_protect_xattr(dentry, xattr_name, xattr_value,
xattr_value_len);
}
result = ima_protect_xattr(dentry, xattr_name, xattr_value,
xattr_value_len);
if (result == 1) {
+ if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST))
+ return -EINVAL;
ima_reset_appraise_flags(dentry->d_inode,
(xvalue->type == EVM_IMA_XATTR_DIGSIG) ? 1 : 0);
result = 0;
EVM_XATTR_HMAC,
EVM_IMA_XATTR_DIGSIG,
IMA_XATTR_DIGEST_NG,
+ IMA_XATTR_LAST
};
struct evm_ima_xattr_data {
if (err < 0)
return err;
+ if (clear_user(src, sizeof(*src)))
+ return -EFAULT;
if (put_user(status.state, &src->state) ||
compat_put_timespec(&status.trigger_tstamp, &src->trigger_tstamp) ||
compat_put_timespec(&status.tstamp, &src->tstamp) ||
#define SAFFIRE_CLOCK_SOURCE_INTERNAL 0
#define SAFFIRE_CLOCK_SOURCE_SPDIF 1
-/* '1' is absent, why... */
+/* clock sources as returned from register of Saffire Pro 10 and 26 */
#define SAFFIREPRO_CLOCK_SOURCE_INTERNAL 0
+#define SAFFIREPRO_CLOCK_SOURCE_SKIP 1 /* never used on hardware */
#define SAFFIREPRO_CLOCK_SOURCE_SPDIF 2
-#define SAFFIREPRO_CLOCK_SOURCE_ADAT1 3
-#define SAFFIREPRO_CLOCK_SOURCE_ADAT2 4
+#define SAFFIREPRO_CLOCK_SOURCE_ADAT1 3 /* not used on s.pro. 10 */
+#define SAFFIREPRO_CLOCK_SOURCE_ADAT2 4 /* not used on s.pro. 10 */
#define SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK 5
+#define SAFFIREPRO_CLOCK_SOURCE_COUNT 6
/* S/PDIF, ADAT1, ADAT2 is enabled or not. three quadlets */
#define SAFFIREPRO_ENABLE_DIG_IFACES 0x01a4
&data, sizeof(__be32), 0);
}
+static char *const saffirepro_10_clk_src_labels[] = {
+ SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "Word Clock"
+};
static char *const saffirepro_26_clk_src_labels[] = {
SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "ADAT1", "ADAT2", "Word Clock"
};
-
-static char *const saffirepro_10_clk_src_labels[] = {
- SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "Word Clock"
+/* Value maps between registers and labels for SaffirePro 10/26. */
+static const signed char saffirepro_clk_maps[][SAFFIREPRO_CLOCK_SOURCE_COUNT] = {
+ /* SaffirePro 10 */
+ [0] = {
+ [SAFFIREPRO_CLOCK_SOURCE_INTERNAL] = 0,
+ [SAFFIREPRO_CLOCK_SOURCE_SKIP] = -1, /* not supported */
+ [SAFFIREPRO_CLOCK_SOURCE_SPDIF] = 1,
+ [SAFFIREPRO_CLOCK_SOURCE_ADAT1] = -1, /* not supported */
+ [SAFFIREPRO_CLOCK_SOURCE_ADAT2] = -1, /* not supported */
+ [SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK] = 2,
+ },
+ /* SaffirePro 26 */
+ [1] = {
+ [SAFFIREPRO_CLOCK_SOURCE_INTERNAL] = 0,
+ [SAFFIREPRO_CLOCK_SOURCE_SKIP] = -1, /* not supported */
+ [SAFFIREPRO_CLOCK_SOURCE_SPDIF] = 1,
+ [SAFFIREPRO_CLOCK_SOURCE_ADAT1] = 2,
+ [SAFFIREPRO_CLOCK_SOURCE_ADAT2] = 3,
+ [SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK] = 4,
+ }
};
+
static int
saffirepro_both_clk_freq_get(struct snd_bebob *bebob, unsigned int *rate)
{
return saffire_write_quad(bebob, SAFFIREPRO_RATE_NOREBOOT, id);
}
+
+/*
+ * query hardware for current clock source, return our internally
+ * used clock index in *id, depending on hardware.
+ */
static int
saffirepro_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id)
{
int err;
- u32 value;
+ u32 value; /* clock source read from hw register */
+ const signed char *map;
err = saffire_read_quad(bebob, SAFFIREPRO_OFFSET_CLOCK_SOURCE, &value);
if (err < 0)
goto end;
- if (bebob->spec->clock->labels == saffirepro_10_clk_src_labels) {
- if (value == SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK)
- *id = 2;
- else if (value == SAFFIREPRO_CLOCK_SOURCE_SPDIF)
- *id = 1;
- } else if (value > 1) {
- *id = value - 1;
+ /* depending on hardware, use a different mapping */
+ if (bebob->spec->clock->labels == saffirepro_10_clk_src_labels)
+ map = saffirepro_clk_maps[0];
+ else
+ map = saffirepro_clk_maps[1];
+
+ /* In a case that this driver cannot handle the value of register. */
+ if (value >= SAFFIREPRO_CLOCK_SOURCE_COUNT || map[value] < 0) {
+ err = -EIO;
+ goto end;
}
+
+ *id = (unsigned int)map[value];
end:
return err;
}
/* 1.The device has its own operation to switch source of clock */
if (clk_spec) {
err = clk_spec->get(bebob, &id);
- if (err < 0)
+ if (err < 0) {
dev_err(&bebob->unit->device,
"fail to get clock source: %d\n", err);
- else if (strncmp(clk_spec->labels[id], SND_BEBOB_CLOCK_INTERNAL,
- strlen(SND_BEBOB_CLOCK_INTERNAL)) == 0)
+ goto end;
+ }
+
+ if (id >= clk_spec->num) {
+ dev_err(&bebob->unit->device,
+ "clock source %d out of range 0..%d\n",
+ id, clk_spec->num - 1);
+ err = -EIO;
+ goto end;
+ }
+
+ if (strncmp(clk_spec->labels[id], SND_BEBOB_CLOCK_INTERNAL,
+ strlen(SND_BEBOB_CLOCK_INTERNAL)) == 0)
*internal = true;
+
goto end;
}
if (err < 0)
goto end;
- *id = (enable_ext & 0x01) | ((enable_word & 0x01) << 1);
+ if (enable_ext == 0)
+ *id = 0;
+ else if (enable_word == 0)
+ *id = 1;
+ else
+ *id = 2;
end:
return err;
}
/* WARQ is at offset 12 */
tmp = (reg & AD_DS_WSMC_WARQ) ?
- (((reg & AD_DS_WSMC_WARQ >> 12) & 0x01) ? 12 : 18) : 4;
+ ((((reg & AD_DS_WSMC_WARQ) >> 12) & 0x01) ? 12 : 18) : 4;
tmp /= (reg & AD_DS_WSMC_WAST) ? 2 : 1;
snd_iprintf(buffer, "Wave FIFO: %d %s words\n\n", tmp,
/* SYRQ is at offset 4 */
tmp = (reg & AD_DS_WSMC_SYRQ) ?
- (((reg & AD_DS_WSMC_SYRQ >> 4) & 0x01) ? 12 : 18) : 4;
+ ((((reg & AD_DS_WSMC_SYRQ) >> 4) & 0x01) ? 12 : 18) : 4;
tmp /= (reg & AD_DS_WSMC_WAST) ? 2 : 1;
snd_iprintf(buffer, "Synthesis FIFO: %d %s words\n\n", tmp,
/* ACRQ is at offset 4 */
tmp = (reg & AD_DS_RAMC_ACRQ) ?
- (((reg & AD_DS_RAMC_ACRQ >> 4) & 0x01) ? 12 : 18) : 4;
+ ((((reg & AD_DS_RAMC_ACRQ) >> 4) & 0x01) ? 12 : 18) : 4;
tmp /= (reg & AD_DS_RAMC_ADST) ? 2 : 1;
snd_iprintf(buffer, "ADC FIFO: %d %s words\n\n", tmp,
/* RERQ is at offset 12 */
tmp = (reg & AD_DS_RAMC_RERQ) ?
- (((reg & AD_DS_RAMC_RERQ >> 12) & 0x01) ? 12 : 18) : 4;
+ ((((reg & AD_DS_RAMC_RERQ) >> 12) & 0x01) ? 12 : 18) : 4;
tmp /= (reg & AD_DS_RAMC_ADST) ? 2 : 1;
snd_iprintf(buffer, "Resampler FIFO: %d %s words\n\n", tmp,
#ifdef CONFIG_SND_DMA_SGBUF
if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG) {
struct snd_sg_buf *sgbuf = dmab->private_data;
+ if (chip->driver_type == AZX_DRIVER_CMEDIA)
+ return; /* deal with only CORB/RIRB buffers */
if (on)
set_pages_array_wc(sgbuf->page_table, sgbuf->pages);
else
#ifdef CONFIG_X86
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
struct azx *chip = apcm->chip;
- if (!azx_snoop(chip))
+ if (!azx_snoop(chip) && chip->driver_type != AZX_DRIVER_CMEDIA)
area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
#endif
}
static struct coef_fw alc282_coefs[] = {
WRITE_COEF(0x03, 0x0002), /* Power Down Control */
- WRITE_COEF(0x05, 0x0700), /* FIFO and filter clock */
+ UPDATE_COEF(0x05, 0xff3f, 0x0700), /* FIFO and filter clock */
WRITE_COEF(0x07, 0x0200), /* DMIC control */
UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */
UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */
static struct coef_fw alc283_coefs[] = {
WRITE_COEF(0x03, 0x0002), /* Power Down Control */
- WRITE_COEF(0x05, 0x0700), /* FIFO and filter clock */
+ UPDATE_COEF(0x05, 0xff3f, 0x0700), /* FIFO and filter clock */
WRITE_COEF(0x07, 0x0200), /* DMIC control */
UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */
UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */
UPDATE_COEF(0x40, 0xf800, 0x9800), /* Class D DC enable */
UPDATE_COEF(0x42, 0xf000, 0x2000), /* DC offset */
WRITE_COEF(0x37, 0xfc06), /* Class D amp control */
+ UPDATE_COEF(0x1b, 0x8000, 0), /* HP JD control */
{}
};
SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0696, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A),
SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
source "sound/soc/pxa/Kconfig"
source "sound/soc/rockchip/Kconfig"
source "sound/soc/samsung/Kconfig"
-source "sound/soc/s6000/Kconfig"
source "sound/soc/sh/Kconfig"
source "sound/soc/sirf/Kconfig"
source "sound/soc/spear/Kconfig"
obj-$(CONFIG_SND_SOC) += pxa/
obj-$(CONFIG_SND_SOC) += rockchip/
obj-$(CONFIG_SND_SOC) += samsung/
-obj-$(CONFIG_SND_SOC) += s6000/
obj-$(CONFIG_SND_SOC) += sh/
obj-$(CONFIG_SND_SOC) += sirf/
obj-$(CONFIG_SND_SOC) += spear/
2, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("Slew Clock", ADAU1761_CLK_ENABLE0, 6, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ALC Clock", ADAU1761_CLK_ENABLE0, 5, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("Digital Clock 0", 1, ADAU1761_CLK_ENABLE1,
0, 0, NULL, 0),
{ "Right Playback Mixer", NULL, "Slew Clock" },
{ "Left Playback Mixer", NULL, "Slew Clock" },
+ { "Left Input Mixer", NULL, "ALC Clock" },
+ { "Right Input Mixer", NULL, "ALC Clock" },
+
{ "Digital Clock 0", NULL, "SYSCLK" },
{ "Digital Clock 1", NULL, "SYSCLK" },
};
return -ENOMEM;
asrc_priv->pdev = pdev;
- strcpy(asrc_priv->name, np->name);
+ strncpy(asrc_priv->name, np->name, sizeof(asrc_priv->name) - 1);
/* Get the addresses and IRQ */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
return -ENOMEM;
esai_priv->pdev = pdev;
- strcpy(esai_priv->name, np->name);
+ strncpy(esai_priv->name, np->name, sizeof(esai_priv->name) - 1);
/* Get the addresses and IRQ */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
}
#define HSW_FORMATS \
- (SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | \
- SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE |\
- SNDRV_PCM_FMTBIT_S8)
+ (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
static struct snd_soc_dai_driver hsw_dais[] = {
{
+++ /dev/null
-config SND_S6000_SOC
- tristate "SoC Audio for the Stretch s6000 family"
- depends on XTENSA_VARIANT_S6000 || COMPILE_TEST
- depends on HAS_IOMEM
- select SND_S6000_SOC_PCM if XTENSA_VARIANT_S6000
- help
- Say Y or M if you want to add support for codecs attached to
- s6000 family chips. You will also need to select the platform
- to support below.
-
-config SND_S6000_SOC_PCM
- tristate
-
-config SND_S6000_SOC_I2S
- tristate
-
-config SND_S6000_SOC_S6IPCAM
- bool "SoC Audio support for Stretch 6105 IP Camera"
- depends on SND_S6000_SOC=y
- depends on I2C=y
- depends on XTENSA_PLATFORM_S6105 || COMPILE_TEST
- select SND_S6000_SOC_I2S
- select SND_SOC_TLV320AIC3X
- help
- Say Y if you want to add support for SoC audio on the
- Stretch s6105 IP Camera Reference Design.
+++ /dev/null
-# s6000 Platform Support
-snd-soc-s6000-objs := s6000-pcm.o
-snd-soc-s6000-i2s-objs := s6000-i2s.o
-
-obj-$(CONFIG_SND_S6000_SOC_PCM) += snd-soc-s6000.o
-obj-$(CONFIG_SND_S6000_SOC_I2S) += snd-soc-s6000-i2s.o
-
-# s6105 Machine Support
-snd-soc-s6ipcam-objs := s6105-ipcam.o
-
-obj-$(CONFIG_SND_S6000_SOC_S6IPCAM) += snd-soc-s6ipcam.o
+++ /dev/null
-/*
- * ALSA SoC I2S Audio Layer for the Stretch S6000 family
- *
- * Author: Daniel Gloeckner, <dg@emlix.com>
- * Copyright: (C) 2009 emlix GmbH <info@emlix.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-
-#include "s6000-i2s.h"
-#include "s6000-pcm.h"
-
-struct s6000_i2s_dev {
- dma_addr_t sifbase;
- u8 __iomem *scbbase;
- unsigned int wide;
- unsigned int channel_in;
- unsigned int channel_out;
- unsigned int lines_in;
- unsigned int lines_out;
- struct s6000_pcm_dma_params dma_params;
-};
-
-#define S6_I2S_INTERRUPT_STATUS 0x00
-#define S6_I2S_INT_OVERRUN 1
-#define S6_I2S_INT_UNDERRUN 2
-#define S6_I2S_INT_ALIGNMENT 4
-#define S6_I2S_INTERRUPT_ENABLE 0x04
-#define S6_I2S_INTERRUPT_RAW 0x08
-#define S6_I2S_INTERRUPT_CLEAR 0x0C
-#define S6_I2S_INTERRUPT_SET 0x10
-#define S6_I2S_MODE 0x20
-#define S6_I2S_DUAL 0
-#define S6_I2S_WIDE 1
-#define S6_I2S_TX_DEFAULT 0x24
-#define S6_I2S_DATA_CFG(c) (0x40 + 0x10 * (c))
-#define S6_I2S_IN 0
-#define S6_I2S_OUT 1
-#define S6_I2S_UNUSED 2
-#define S6_I2S_INTERFACE_CFG(c) (0x44 + 0x10 * (c))
-#define S6_I2S_DIV_MASK 0x001fff
-#define S6_I2S_16BIT 0x000000
-#define S6_I2S_20BIT 0x002000
-#define S6_I2S_24BIT 0x004000
-#define S6_I2S_32BIT 0x006000
-#define S6_I2S_BITS_MASK 0x006000
-#define S6_I2S_MEM_16BIT 0x000000
-#define S6_I2S_MEM_32BIT 0x008000
-#define S6_I2S_MEM_MASK 0x008000
-#define S6_I2S_CHANNELS_SHIFT 16
-#define S6_I2S_CHANNELS_MASK 0x030000
-#define S6_I2S_SCK_IN 0x000000
-#define S6_I2S_SCK_OUT 0x040000
-#define S6_I2S_SCK_DIR 0x040000
-#define S6_I2S_WS_IN 0x000000
-#define S6_I2S_WS_OUT 0x080000
-#define S6_I2S_WS_DIR 0x080000
-#define S6_I2S_LEFT_FIRST 0x000000
-#define S6_I2S_RIGHT_FIRST 0x100000
-#define S6_I2S_FIRST 0x100000
-#define S6_I2S_CUR_SCK 0x200000
-#define S6_I2S_CUR_WS 0x400000
-#define S6_I2S_ENABLE(c) (0x48 + 0x10 * (c))
-#define S6_I2S_DISABLE_IF 0x02
-#define S6_I2S_ENABLE_IF 0x03
-#define S6_I2S_IS_BUSY 0x04
-#define S6_I2S_DMA_ACTIVE 0x08
-#define S6_I2S_IS_ENABLED 0x10
-
-#define S6_I2S_NUM_LINES 4
-
-#define S6_I2S_SIF_PORT0 0x0000000
-#define S6_I2S_SIF_PORT1 0x0000080 /* docs say 0x0000010 */
-
-static inline void s6_i2s_write_reg(struct s6000_i2s_dev *dev, int reg, u32 val)
-{
- writel(val, dev->scbbase + reg);
-}
-
-static inline u32 s6_i2s_read_reg(struct s6000_i2s_dev *dev, int reg)
-{
- return readl(dev->scbbase + reg);
-}
-
-static inline void s6_i2s_mod_reg(struct s6000_i2s_dev *dev, int reg,
- u32 mask, u32 val)
-{
- val ^= s6_i2s_read_reg(dev, reg) & ~mask;
- s6_i2s_write_reg(dev, reg, val);
-}
-
-static void s6000_i2s_start_channel(struct s6000_i2s_dev *dev, int channel)
-{
- int i, j, cur, prev;
-
- /*
- * Wait for WCLK to toggle 5 times before enabling the channel
- * s6000 Family Datasheet 3.6.4:
- * "At least two cycles of WS must occur between commands
- * to disable or enable the interface"
- */
- j = 0;
- prev = ~S6_I2S_CUR_WS;
- for (i = 1000000; --i && j < 6; ) {
- cur = s6_i2s_read_reg(dev, S6_I2S_INTERFACE_CFG(channel))
- & S6_I2S_CUR_WS;
- if (prev != cur) {
- prev = cur;
- j++;
- }
- }
- if (j < 6)
- printk(KERN_WARNING "s6000-i2s: timeout waiting for WCLK\n");
-
- s6_i2s_write_reg(dev, S6_I2S_ENABLE(channel), S6_I2S_ENABLE_IF);
-}
-
-static void s6000_i2s_stop_channel(struct s6000_i2s_dev *dev, int channel)
-{
- s6_i2s_write_reg(dev, S6_I2S_ENABLE(channel), S6_I2S_DISABLE_IF);
-}
-
-static void s6000_i2s_start(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai);
- int channel;
-
- channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
- dev->channel_out : dev->channel_in;
-
- s6000_i2s_start_channel(dev, channel);
-}
-
-static void s6000_i2s_stop(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai);
- int channel;
-
- channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
- dev->channel_out : dev->channel_in;
-
- s6000_i2s_stop_channel(dev, channel);
-}
-
-static int s6000_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
- int after)
-{
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) ^ !after)
- s6000_i2s_start(substream);
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- if (!after)
- s6000_i2s_stop(substream);
- }
- return 0;
-}
-
-static unsigned int s6000_i2s_int_sources(struct s6000_i2s_dev *dev)
-{
- unsigned int pending;
- pending = s6_i2s_read_reg(dev, S6_I2S_INTERRUPT_RAW);
- pending &= S6_I2S_INT_ALIGNMENT |
- S6_I2S_INT_UNDERRUN |
- S6_I2S_INT_OVERRUN;
- s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_CLEAR, pending);
-
- return pending;
-}
-
-static unsigned int s6000_i2s_check_xrun(struct snd_soc_dai *cpu_dai)
-{
- struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
- unsigned int errors;
- unsigned int ret;
-
- errors = s6000_i2s_int_sources(dev);
- if (likely(!errors))
- return 0;
-
- ret = 0;
- if (errors & S6_I2S_INT_ALIGNMENT)
- printk(KERN_ERR "s6000-i2s: WCLK misaligned\n");
- if (errors & S6_I2S_INT_UNDERRUN)
- ret |= 1 << SNDRV_PCM_STREAM_PLAYBACK;
- if (errors & S6_I2S_INT_OVERRUN)
- ret |= 1 << SNDRV_PCM_STREAM_CAPTURE;
- return ret;
-}
-
-static void s6000_i2s_wait_disabled(struct s6000_i2s_dev *dev)
-{
- int channel;
- int n = 50;
- for (channel = 0; channel < 2; channel++) {
- while (--n >= 0) {
- int v = s6_i2s_read_reg(dev, S6_I2S_ENABLE(channel));
- if ((v & S6_I2S_IS_ENABLED)
- || !(v & (S6_I2S_DMA_ACTIVE | S6_I2S_IS_BUSY)))
- break;
- udelay(20);
- }
- }
- if (n < 0)
- printk(KERN_WARNING "s6000-i2s: timeout disabling interfaces");
-}
-
-static int s6000_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
- unsigned int fmt)
-{
- struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
- u32 w;
-
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
- w = S6_I2S_SCK_IN | S6_I2S_WS_IN;
- break;
- case SND_SOC_DAIFMT_CBS_CFM:
- w = S6_I2S_SCK_OUT | S6_I2S_WS_IN;
- break;
- case SND_SOC_DAIFMT_CBM_CFS:
- w = S6_I2S_SCK_IN | S6_I2S_WS_OUT;
- break;
- case SND_SOC_DAIFMT_CBS_CFS:
- w = S6_I2S_SCK_OUT | S6_I2S_WS_OUT;
- break;
- default:
- return -EINVAL;
- }
-
- switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
- case SND_SOC_DAIFMT_NB_NF:
- w |= S6_I2S_LEFT_FIRST;
- break;
- case SND_SOC_DAIFMT_NB_IF:
- w |= S6_I2S_RIGHT_FIRST;
- break;
- default:
- return -EINVAL;
- }
-
- s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(0),
- S6_I2S_FIRST | S6_I2S_WS_DIR | S6_I2S_SCK_DIR, w);
- s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(1),
- S6_I2S_FIRST | S6_I2S_WS_DIR | S6_I2S_SCK_DIR, w);
-
- return 0;
-}
-
-static int s6000_i2s_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
-{
- struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
-
- if (!div || (div & 1) || div > (S6_I2S_DIV_MASK + 1) * 2)
- return -EINVAL;
-
- s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(div_id),
- S6_I2S_DIV_MASK, div / 2 - 1);
- return 0;
-}
-
-static int s6000_i2s_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
-{
- struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
- int interf;
- u32 w = 0;
-
- if (dev->wide)
- interf = 0;
- else {
- w |= (((params_channels(params) - 2) / 2)
- << S6_I2S_CHANNELS_SHIFT) & S6_I2S_CHANNELS_MASK;
- interf = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- ? dev->channel_out : dev->channel_in;
- }
-
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
- w |= S6_I2S_16BIT | S6_I2S_MEM_16BIT;
- break;
- case SNDRV_PCM_FORMAT_S32_LE:
- w |= S6_I2S_32BIT | S6_I2S_MEM_32BIT;
- break;
- default:
- printk(KERN_WARNING "s6000-i2s: unsupported PCM format %x\n",
- params_format(params));
- return -EINVAL;
- }
-
- if (s6_i2s_read_reg(dev, S6_I2S_INTERFACE_CFG(interf))
- & S6_I2S_IS_ENABLED) {
- printk(KERN_ERR "s6000-i2s: interface already enabled\n");
- return -EBUSY;
- }
-
- s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(interf),
- S6_I2S_CHANNELS_MASK|S6_I2S_MEM_MASK|S6_I2S_BITS_MASK,
- w);
-
- return 0;
-}
-
-static int s6000_i2s_dai_probe(struct snd_soc_dai *dai)
-{
- struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
- struct s6000_snd_platform_data *pdata = dai->dev->platform_data;
-
- if (!pdata)
- return -EINVAL;
-
- dai->capture_dma_data = &dev->dma_params;
- dai->playback_dma_data = &dev->dma_params;
-
- dev->wide = pdata->wide;
- dev->channel_in = pdata->channel_in;
- dev->channel_out = pdata->channel_out;
- dev->lines_in = pdata->lines_in;
- dev->lines_out = pdata->lines_out;
-
- s6_i2s_write_reg(dev, S6_I2S_MODE,
- dev->wide ? S6_I2S_WIDE : S6_I2S_DUAL);
-
- if (dev->wide) {
- int i;
-
- if (dev->lines_in + dev->lines_out > S6_I2S_NUM_LINES)
- return -EINVAL;
-
- dev->channel_in = 0;
- dev->channel_out = 1;
- dai->driver->capture.channels_min = 2 * dev->lines_in;
- dai->driver->capture.channels_max = dai->driver->capture.channels_min;
- dai->driver->playback.channels_min = 2 * dev->lines_out;
- dai->driver->playback.channels_max = dai->driver->playback.channels_min;
-
- for (i = 0; i < dev->lines_out; i++)
- s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), S6_I2S_OUT);
-
- for (; i < S6_I2S_NUM_LINES - dev->lines_in; i++)
- s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i),
- S6_I2S_UNUSED);
-
- for (; i < S6_I2S_NUM_LINES; i++)
- s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), S6_I2S_IN);
- } else {
- unsigned int cfg[2] = {S6_I2S_UNUSED, S6_I2S_UNUSED};
-
- if (dev->lines_in > 1 || dev->lines_out > 1)
- return -EINVAL;
-
- dai->driver->capture.channels_min = 2 * dev->lines_in;
- dai->driver->capture.channels_max = 8 * dev->lines_in;
- dai->driver->playback.channels_min = 2 * dev->lines_out;
- dai->driver->playback.channels_max = 8 * dev->lines_out;
-
- if (dev->lines_in)
- cfg[dev->channel_in] = S6_I2S_IN;
- if (dev->lines_out)
- cfg[dev->channel_out] = S6_I2S_OUT;
-
- s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(0), cfg[0]);
- s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(1), cfg[1]);
- }
-
- if (dev->lines_out) {
- if (dev->lines_in) {
- if (!dev->dma_params.dma_out)
- return -ENODEV;
- } else {
- dev->dma_params.dma_out = dev->dma_params.dma_in;
- dev->dma_params.dma_in = 0;
- }
- }
- dev->dma_params.sif_in = dev->sifbase + (dev->channel_in ?
- S6_I2S_SIF_PORT1 : S6_I2S_SIF_PORT0);
- dev->dma_params.sif_out = dev->sifbase + (dev->channel_out ?
- S6_I2S_SIF_PORT1 : S6_I2S_SIF_PORT0);
- dev->dma_params.same_rate = pdata->same_rate | pdata->wide;
- return 0;
-}
-
-#define S6000_I2S_RATES SNDRV_PCM_RATE_CONTINUOUS
-#define S6000_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
-
-static const struct snd_soc_dai_ops s6000_i2s_dai_ops = {
- .set_fmt = s6000_i2s_set_dai_fmt,
- .set_clkdiv = s6000_i2s_set_clkdiv,
- .hw_params = s6000_i2s_hw_params,
-};
-
-static struct snd_soc_dai_driver s6000_i2s_dai = {
- .probe = s6000_i2s_dai_probe,
- .playback = {
- .channels_min = 2,
- .channels_max = 8,
- .formats = S6000_I2S_FORMATS,
- .rates = S6000_I2S_RATES,
- .rate_min = 0,
- .rate_max = 1562500,
- },
- .capture = {
- .channels_min = 2,
- .channels_max = 8,
- .formats = S6000_I2S_FORMATS,
- .rates = S6000_I2S_RATES,
- .rate_min = 0,
- .rate_max = 1562500,
- },
- .ops = &s6000_i2s_dai_ops,
-};
-
-static const struct snd_soc_component_driver s6000_i2s_component = {
- .name = "s6000-i2s",
-};
-
-static int s6000_i2s_probe(struct platform_device *pdev)
-{
- struct s6000_i2s_dev *dev;
- struct resource *scbmem, *sifmem, *region, *dma1, *dma2;
- u8 __iomem *mmio;
- int ret;
-
- scbmem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!scbmem) {
- dev_err(&pdev->dev, "no mem resource?\n");
- ret = -ENODEV;
- goto err_release_none;
- }
-
- region = request_mem_region(scbmem->start, resource_size(scbmem),
- pdev->name);
- if (!region) {
- dev_err(&pdev->dev, "I2S SCB region already claimed\n");
- ret = -EBUSY;
- goto err_release_none;
- }
-
- mmio = ioremap(scbmem->start, resource_size(scbmem));
- if (!mmio) {
- dev_err(&pdev->dev, "can't ioremap SCB region\n");
- ret = -ENOMEM;
- goto err_release_scb;
- }
-
- sifmem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!sifmem) {
- dev_err(&pdev->dev, "no second mem resource?\n");
- ret = -ENODEV;
- goto err_release_map;
- }
-
- region = request_mem_region(sifmem->start, resource_size(sifmem),
- pdev->name);
- if (!region) {
- dev_err(&pdev->dev, "I2S SIF region already claimed\n");
- ret = -EBUSY;
- goto err_release_map;
- }
-
- dma1 = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!dma1) {
- dev_err(&pdev->dev, "no dma resource?\n");
- ret = -ENODEV;
- goto err_release_sif;
- }
-
- region = request_mem_region(dma1->start, resource_size(dma1),
- pdev->name);
- if (!region) {
- dev_err(&pdev->dev, "I2S DMA region already claimed\n");
- ret = -EBUSY;
- goto err_release_sif;
- }
-
- dma2 = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (dma2) {
- region = request_mem_region(dma2->start, resource_size(dma2),
- pdev->name);
- if (!region) {
- dev_err(&pdev->dev,
- "I2S DMA region already claimed\n");
- ret = -EBUSY;
- goto err_release_dma1;
- }
- }
-
- dev = kzalloc(sizeof(struct s6000_i2s_dev), GFP_KERNEL);
- if (!dev) {
- ret = -ENOMEM;
- goto err_release_dma2;
- }
- dev_set_drvdata(&pdev->dev, dev);
-
- dev->sifbase = sifmem->start;
- dev->scbbase = mmio;
-
- s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, 0);
- s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_CLEAR,
- S6_I2S_INT_ALIGNMENT |
- S6_I2S_INT_UNDERRUN |
- S6_I2S_INT_OVERRUN);
-
- s6000_i2s_stop_channel(dev, 0);
- s6000_i2s_stop_channel(dev, 1);
- s6000_i2s_wait_disabled(dev);
-
- dev->dma_params.check_xrun = s6000_i2s_check_xrun;
- dev->dma_params.trigger = s6000_i2s_trigger;
- dev->dma_params.dma_in = dma1->start;
- dev->dma_params.dma_out = dma2 ? dma2->start : 0;
- dev->dma_params.irq = platform_get_irq(pdev, 0);
- if (dev->dma_params.irq < 0) {
- dev_err(&pdev->dev, "no irq resource?\n");
- ret = -ENODEV;
- goto err_release_dev;
- }
-
- s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE,
- S6_I2S_INT_ALIGNMENT |
- S6_I2S_INT_UNDERRUN |
- S6_I2S_INT_OVERRUN);
-
- ret = snd_soc_register_component(&pdev->dev, &s6000_i2s_component,
- &s6000_i2s_dai, 1);
- if (ret)
- goto err_release_dev;
-
- return 0;
-
-err_release_dev:
- kfree(dev);
-err_release_dma2:
- if (dma2)
- release_mem_region(dma2->start, resource_size(dma2));
-err_release_dma1:
- release_mem_region(dma1->start, resource_size(dma1));
-err_release_sif:
- release_mem_region(sifmem->start, resource_size(sifmem));
-err_release_map:
- iounmap(mmio);
-err_release_scb:
- release_mem_region(scbmem->start, resource_size(scbmem));
-err_release_none:
- return ret;
-}
-
-static int s6000_i2s_remove(struct platform_device *pdev)
-{
- struct s6000_i2s_dev *dev = dev_get_drvdata(&pdev->dev);
- struct resource *region;
- void __iomem *mmio = dev->scbbase;
-
- snd_soc_unregister_component(&pdev->dev);
-
- s6000_i2s_stop_channel(dev, 0);
- s6000_i2s_stop_channel(dev, 1);
-
- s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, 0);
- kfree(dev);
-
- region = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- release_mem_region(region->start, resource_size(region));
-
- region = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (region)
- release_mem_region(region->start, resource_size(region));
-
- region = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(region->start, resource_size(region));
-
- iounmap(mmio);
- region = platform_get_resource(pdev, IORESOURCE_IO, 0);
- release_mem_region(region->start, resource_size(region));
-
- return 0;
-}
-
-static struct platform_driver s6000_i2s_driver = {
- .probe = s6000_i2s_probe,
- .remove = s6000_i2s_remove,
- .driver = {
- .name = "s6000-i2s",
- .owner = THIS_MODULE,
- },
-};
-
-module_platform_driver(s6000_i2s_driver);
-
-MODULE_AUTHOR("Daniel Gloeckner");
-MODULE_DESCRIPTION("Stretch s6000 family I2S SoC Interface");
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * ALSA SoC I2S Audio Layer for the Stretch s6000 family
- *
- * Author: Daniel Gloeckner, <dg@emlix.com>
- * Copyright: (C) 2009 emlix GmbH <info@emlix.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _S6000_I2S_H
-#define _S6000_I2S_H
-
-struct s6000_snd_platform_data {
- int lines_in;
- int lines_out;
- int channel_in;
- int channel_out;
- int wide;
- int same_rate;
-};
-#endif
+++ /dev/null
-/*
- * ALSA PCM interface for the Stetch s6000 family
- *
- * Author: Daniel Gloeckner, <dg@emlix.com>
- * Copyright: (C) 2009 emlix GmbH <info@emlix.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/dma-mapping.h>
-#include <linux/interrupt.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <asm/dma.h>
-#include <variant/dmac.h>
-
-#include "s6000-pcm.h"
-
-#define S6_PCM_PREALLOCATE_SIZE (96 * 1024)
-#define S6_PCM_PREALLOCATE_MAX (2048 * 1024)
-
-static struct snd_pcm_hardware s6000_pcm_hardware = {
- .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_JOINT_DUPLEX),
- .buffer_bytes_max = 0x7ffffff0,
- .period_bytes_min = 16,
- .period_bytes_max = 0xfffff0,
- .periods_min = 2,
- .periods_max = 1024, /* no limit */
- .fifo_size = 0,
-};
-
-struct s6000_runtime_data {
- spinlock_t lock;
- int period; /* current DMA period */
-};
-
-static void s6000_pcm_enqueue_dma(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct s6000_runtime_data *prtd = runtime->private_data;
- struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
- struct s6000_pcm_dma_params *par;
- int channel;
- unsigned int period_size;
- unsigned int dma_offset;
- dma_addr_t dma_pos;
- dma_addr_t src, dst;
-
- par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
-
- period_size = snd_pcm_lib_period_bytes(substream);
- dma_offset = prtd->period * period_size;
- dma_pos = runtime->dma_addr + dma_offset;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- src = dma_pos;
- dst = par->sif_out;
- channel = par->dma_out;
- } else {
- src = par->sif_in;
- dst = dma_pos;
- channel = par->dma_in;
- }
-
- if (!s6dmac_channel_enabled(DMA_MASK_DMAC(channel),
- DMA_INDEX_CHNL(channel)))
- return;
-
- if (s6dmac_fifo_full(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel))) {
- printk(KERN_ERR "s6000-pcm: fifo full\n");
- return;
- }
-
- if (WARN_ON(period_size & 15))
- return;
- s6dmac_put_fifo(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel),
- src, dst, period_size);
-
- prtd->period++;
- if (unlikely(prtd->period >= runtime->periods))
- prtd->period = 0;
-}
-
-static irqreturn_t s6000_pcm_irq(int irq, void *data)
-{
- struct snd_pcm *pcm = data;
- struct snd_soc_pcm_runtime *runtime = pcm->private_data;
- struct s6000_runtime_data *prtd;
- unsigned int has_xrun;
- int i, ret = IRQ_NONE;
-
- for (i = 0; i < 2; ++i) {
- struct snd_pcm_substream *substream = pcm->streams[i].substream;
- struct s6000_pcm_dma_params *params =
- snd_soc_dai_get_dma_data(runtime->cpu_dai, substream);
- u32 channel;
- unsigned int pending;
-
- if (substream == SNDRV_PCM_STREAM_PLAYBACK)
- channel = params->dma_out;
- else
- channel = params->dma_in;
-
- has_xrun = params->check_xrun(runtime->cpu_dai);
-
- if (!channel)
- continue;
-
- if (unlikely(has_xrun & (1 << i)) &&
- substream->runtime &&
- snd_pcm_running(substream)) {
- dev_dbg(pcm->dev, "xrun\n");
- snd_pcm_stream_lock(substream);
- snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock(substream);
- ret = IRQ_HANDLED;
- }
-
- pending = s6dmac_int_sources(DMA_MASK_DMAC(channel),
- DMA_INDEX_CHNL(channel));
-
- if (pending & 1) {
- ret = IRQ_HANDLED;
- if (likely(substream->runtime &&
- snd_pcm_running(substream))) {
- snd_pcm_period_elapsed(substream);
- dev_dbg(pcm->dev, "period elapsed %x %x\n",
- s6dmac_cur_src(DMA_MASK_DMAC(channel),
- DMA_INDEX_CHNL(channel)),
- s6dmac_cur_dst(DMA_MASK_DMAC(channel),
- DMA_INDEX_CHNL(channel)));
- prtd = substream->runtime->private_data;
- spin_lock(&prtd->lock);
- s6000_pcm_enqueue_dma(substream);
- spin_unlock(&prtd->lock);
- }
- }
-
- if (unlikely(pending & ~7)) {
- if (pending & (1 << 3))
- printk(KERN_WARNING
- "s6000-pcm: DMA %x Underflow\n",
- channel);
- if (pending & (1 << 4))
- printk(KERN_WARNING
- "s6000-pcm: DMA %x Overflow\n",
- channel);
- if (pending & 0x1e0)
- printk(KERN_WARNING
- "s6000-pcm: DMA %x Master Error "
- "(mask %x)\n",
- channel, pending >> 5);
-
- }
- }
-
- return ret;
-}
-
-static int s6000_pcm_start(struct snd_pcm_substream *substream)
-{
- struct s6000_runtime_data *prtd = substream->runtime->private_data;
- struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
- struct s6000_pcm_dma_params *par;
- unsigned long flags;
- int srcinc;
- u32 dma;
-
- par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
-
- spin_lock_irqsave(&prtd->lock, flags);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- srcinc = 1;
- dma = par->dma_out;
- } else {
- srcinc = 0;
- dma = par->dma_in;
- }
- s6dmac_enable_chan(DMA_MASK_DMAC(dma), DMA_INDEX_CHNL(dma),
- 1 /* priority 1 (0 is max) */,
- 0 /* peripheral requests w/o xfer length mode */,
- srcinc /* source address increment */,
- srcinc^1 /* destination address increment */,
- 0 /* chunksize 0 (skip impossible on this dma) */,
- 0 /* source skip after chunk (impossible) */,
- 0 /* destination skip after chunk (impossible) */,
- 4 /* 16 byte burst size */,
- -1 /* don't conserve bandwidth */,
- 0 /* low watermark irq descriptor threshold */,
- 0 /* disable hardware timestamps */,
- 1 /* enable channel */);
-
- s6000_pcm_enqueue_dma(substream);
- s6000_pcm_enqueue_dma(substream);
-
- spin_unlock_irqrestore(&prtd->lock, flags);
-
- return 0;
-}
-
-static int s6000_pcm_stop(struct snd_pcm_substream *substream)
-{
- struct s6000_runtime_data *prtd = substream->runtime->private_data;
- struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
- struct s6000_pcm_dma_params *par;
- unsigned long flags;
- u32 channel;
-
- par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- channel = par->dma_out;
- else
- channel = par->dma_in;
-
- s6dmac_set_terminal_count(DMA_MASK_DMAC(channel),
- DMA_INDEX_CHNL(channel), 0);
-
- spin_lock_irqsave(&prtd->lock, flags);
-
- s6dmac_disable_chan(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel));
-
- spin_unlock_irqrestore(&prtd->lock, flags);
-
- return 0;
-}
-
-static int s6000_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
- struct s6000_pcm_dma_params *par;
- int ret;
-
- par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
-
- ret = par->trigger(substream, cmd, 0);
- if (ret < 0)
- return ret;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- ret = s6000_pcm_start(substream);
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- ret = s6000_pcm_stop(substream);
- break;
- default:
- ret = -EINVAL;
- }
- if (ret < 0)
- return ret;
-
- return par->trigger(substream, cmd, 1);
-}
-
-static int s6000_pcm_prepare(struct snd_pcm_substream *substream)
-{
- struct s6000_runtime_data *prtd = substream->runtime->private_data;
-
- prtd->period = 0;
-
- return 0;
-}
-
-static snd_pcm_uframes_t s6000_pcm_pointer(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
- struct s6000_pcm_dma_params *par;
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct s6000_runtime_data *prtd = runtime->private_data;
- unsigned long flags;
- unsigned int offset;
- dma_addr_t count;
-
- par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
-
- spin_lock_irqsave(&prtd->lock, flags);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- count = s6dmac_cur_src(DMA_MASK_DMAC(par->dma_out),
- DMA_INDEX_CHNL(par->dma_out));
- else
- count = s6dmac_cur_dst(DMA_MASK_DMAC(par->dma_in),
- DMA_INDEX_CHNL(par->dma_in));
-
- count -= runtime->dma_addr;
-
- spin_unlock_irqrestore(&prtd->lock, flags);
-
- offset = bytes_to_frames(runtime, count);
- if (unlikely(offset >= runtime->buffer_size))
- offset = 0;
-
- return offset;
-}
-
-static int s6000_pcm_open(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
- struct s6000_pcm_dma_params *par;
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct s6000_runtime_data *prtd;
- int ret;
-
- par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
- snd_soc_set_runtime_hwparams(substream, &s6000_pcm_hardware);
-
- ret = snd_pcm_hw_constraint_step(runtime, 0,
- SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 16);
- if (ret < 0)
- return ret;
- ret = snd_pcm_hw_constraint_step(runtime, 0,
- SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16);
- if (ret < 0)
- return ret;
- ret = snd_pcm_hw_constraint_integer(runtime,
- SNDRV_PCM_HW_PARAM_PERIODS);
- if (ret < 0)
- return ret;
-
- if (par->same_rate) {
- int rate;
- spin_lock(&par->lock); /* needed? */
- rate = par->rate;
- spin_unlock(&par->lock);
- if (rate != -1) {
- ret = snd_pcm_hw_constraint_minmax(runtime,
- SNDRV_PCM_HW_PARAM_RATE,
- rate, rate);
- if (ret < 0)
- return ret;
- }
- }
-
- prtd = kzalloc(sizeof(struct s6000_runtime_data), GFP_KERNEL);
- if (prtd == NULL)
- return -ENOMEM;
-
- spin_lock_init(&prtd->lock);
-
- runtime->private_data = prtd;
-
- return 0;
-}
-
-static int s6000_pcm_close(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct s6000_runtime_data *prtd = runtime->private_data;
-
- kfree(prtd);
-
- return 0;
-}
-
-static int s6000_pcm_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
- struct s6000_pcm_dma_params *par;
- int ret;
- ret = snd_pcm_lib_malloc_pages(substream,
- params_buffer_bytes(hw_params));
- if (ret < 0) {
- printk(KERN_WARNING "s6000-pcm: allocation of memory failed\n");
- return ret;
- }
-
- par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
-
- if (par->same_rate) {
- spin_lock(&par->lock);
- if (par->rate == -1 ||
- !(par->in_use & ~(1 << substream->stream))) {
- par->rate = params_rate(hw_params);
- par->in_use |= 1 << substream->stream;
- } else if (params_rate(hw_params) != par->rate) {
- snd_pcm_lib_free_pages(substream);
- par->in_use &= ~(1 << substream->stream);
- ret = -EBUSY;
- }
- spin_unlock(&par->lock);
- }
- return ret;
-}
-
-static int s6000_pcm_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
- struct s6000_pcm_dma_params *par =
- snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
-
- spin_lock(&par->lock);
- par->in_use &= ~(1 << substream->stream);
- if (!par->in_use)
- par->rate = -1;
- spin_unlock(&par->lock);
-
- return snd_pcm_lib_free_pages(substream);
-}
-
-static struct snd_pcm_ops s6000_pcm_ops = {
- .open = s6000_pcm_open,
- .close = s6000_pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = s6000_pcm_hw_params,
- .hw_free = s6000_pcm_hw_free,
- .trigger = s6000_pcm_trigger,
- .prepare = s6000_pcm_prepare,
- .pointer = s6000_pcm_pointer,
-};
-
-static void s6000_pcm_free(struct snd_pcm *pcm)
-{
- struct snd_soc_pcm_runtime *runtime = pcm->private_data;
- struct s6000_pcm_dma_params *params =
- snd_soc_dai_get_dma_data(runtime->cpu_dai,
- pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream);
-
- free_irq(params->irq, pcm);
- snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
-static int s6000_pcm_new(struct snd_soc_pcm_runtime *runtime)
-{
- struct snd_card *card = runtime->card->snd_card;
- struct snd_pcm *pcm = runtime->pcm;
- struct s6000_pcm_dma_params *params;
- int res;
-
- params = snd_soc_dai_get_dma_data(runtime->cpu_dai,
- pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream);
-
- res = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
- if (res)
- return res;
-
- if (params->dma_in) {
- s6dmac_disable_chan(DMA_MASK_DMAC(params->dma_in),
- DMA_INDEX_CHNL(params->dma_in));
- s6dmac_int_sources(DMA_MASK_DMAC(params->dma_in),
- DMA_INDEX_CHNL(params->dma_in));
- }
-
- if (params->dma_out) {
- s6dmac_disable_chan(DMA_MASK_DMAC(params->dma_out),
- DMA_INDEX_CHNL(params->dma_out));
- s6dmac_int_sources(DMA_MASK_DMAC(params->dma_out),
- DMA_INDEX_CHNL(params->dma_out));
- }
-
- res = request_irq(params->irq, s6000_pcm_irq, IRQF_SHARED,
- "s6000-audio", pcm);
- if (res) {
- printk(KERN_ERR "s6000-pcm couldn't get IRQ\n");
- return res;
- }
-
- res = snd_pcm_lib_preallocate_pages_for_all(pcm,
- SNDRV_DMA_TYPE_DEV,
- card->dev,
- S6_PCM_PREALLOCATE_SIZE,
- S6_PCM_PREALLOCATE_MAX);
- if (res)
- printk(KERN_WARNING "s6000-pcm: preallocation failed\n");
-
- spin_lock_init(¶ms->lock);
- params->in_use = 0;
- params->rate = -1;
- return 0;
-}
-
-static struct snd_soc_platform_driver s6000_soc_platform = {
- .ops = &s6000_pcm_ops,
- .pcm_new = s6000_pcm_new,
- .pcm_free = s6000_pcm_free,
-};
-
-static int s6000_soc_platform_probe(struct platform_device *pdev)
-{
- return snd_soc_register_platform(&pdev->dev, &s6000_soc_platform);
-}
-
-static int s6000_soc_platform_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_platform(&pdev->dev);
- return 0;
-}
-
-static struct platform_driver s6000_pcm_driver = {
- .driver = {
- .name = "s6000-pcm-audio",
- .owner = THIS_MODULE,
- },
-
- .probe = s6000_soc_platform_probe,
- .remove = s6000_soc_platform_remove,
-};
-
-module_platform_driver(s6000_pcm_driver);
-
-MODULE_AUTHOR("Daniel Gloeckner");
-MODULE_DESCRIPTION("Stretch s6000 family PCM DMA module");
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * ALSA PCM interface for the Stretch s6000 family
- *
- * Author: Daniel Gloeckner, <dg@emlix.com>
- * Copyright: (C) 2009 emlix GmbH <info@emlix.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _S6000_PCM_H
-#define _S6000_PCM_H
-
-struct snd_soc_dai;
-struct snd_pcm_substream;
-
-struct s6000_pcm_dma_params {
- unsigned int (*check_xrun)(struct snd_soc_dai *cpu_dai);
- int (*trigger)(struct snd_pcm_substream *substream, int cmd, int after);
- dma_addr_t sif_in;
- dma_addr_t sif_out;
- u32 dma_in;
- u32 dma_out;
- int irq;
- int same_rate;
-
- spinlock_t lock;
- int in_use;
- int rate;
-};
-
-#endif
+++ /dev/null
-/*
- * ASoC driver for Stretch s6105 IP camera platform
- *
- * Author: Daniel Gloeckner, <dg@emlix.com>
- * Copyright: (C) 2009 emlix GmbH <info@emlix.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/i2c.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include "s6000-pcm.h"
-#include "s6000-i2s.h"
-
-#define S6105_CAM_CODEC_CLOCK 12288000
-
-static int s6105_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int ret = 0;
-
- /* set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- /* set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM |
- SND_SOC_DAIFMT_NB_NF);
- if (ret < 0)
- return ret;
-
- /* set the codec system clock */
- ret = snd_soc_dai_set_sysclk(codec_dai, 0, S6105_CAM_CODEC_CLOCK,
- SND_SOC_CLOCK_OUT);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static struct snd_soc_ops s6105_ops = {
- .hw_params = s6105_hw_params,
-};
-
-/* s6105 machine dapm widgets */
-static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
- SND_SOC_DAPM_LINE("Audio Out Differential", NULL),
- SND_SOC_DAPM_LINE("Audio Out Stereo", NULL),
- SND_SOC_DAPM_LINE("Audio In", NULL),
-};
-
-/* s6105 machine audio_mapnections to the codec pins */
-static const struct snd_soc_dapm_route audio_map[] = {
- /* Audio Out connected to HPLOUT, HPLCOM, HPROUT */
- {"Audio Out Differential", NULL, "HPLOUT"},
- {"Audio Out Differential", NULL, "HPLCOM"},
- {"Audio Out Stereo", NULL, "HPLOUT"},
- {"Audio Out Stereo", NULL, "HPROUT"},
-
- /* Audio In connected to LINE1L, LINE1R */
- {"LINE1L", NULL, "Audio In"},
- {"LINE1R", NULL, "Audio In"},
-};
-
-static int output_type_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item) {
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, "HPLOUT/HPROUT");
- } else {
- strcpy(uinfo->value.enumerated.name, "HPLOUT/HPLCOM");
- }
- return 0;
-}
-
-static int output_type_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.enumerated.item[0] = kcontrol->private_value;
- return 0;
-}
-
-static int output_type_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_card *card = kcontrol->private_data;
- struct snd_soc_dapm_context *dapm = &card->dapm;
- unsigned int val = (ucontrol->value.enumerated.item[0] != 0);
- char *differential = "Audio Out Differential";
- char *stereo = "Audio Out Stereo";
-
- if (kcontrol->private_value == val)
- return 0;
- kcontrol->private_value = val;
- snd_soc_dapm_disable_pin(dapm, val ? differential : stereo);
- snd_soc_dapm_sync(dapm);
- snd_soc_dapm_enable_pin(dapm, val ? stereo : differential);
- snd_soc_dapm_sync(dapm);
-
- return 1;
-}
-
-static const struct snd_kcontrol_new audio_out_mux = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Master Output Mux",
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = output_type_info,
- .get = output_type_get,
- .put = output_type_put,
- .private_value = 1 /* default to stereo */
-};
-
-/* Logic for a aic3x as connected on the s6105 ip camera ref design */
-static int s6105_aic3x_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_card *card = rtd->card;
-
- /* must correspond to audio_out_mux.private_value initializer */
- snd_soc_dapm_disable_pin(&card->dapm, "Audio Out Differential");
-
- snd_ctl_add(card->snd_card, snd_ctl_new1(&audio_out_mux, card));
-
- return 0;
-}
-
-/* s6105 digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link s6105_dai = {
- .name = "TLV320AIC31",
- .stream_name = "AIC31",
- .cpu_dai_name = "s6000-i2s",
- .codec_dai_name = "tlv320aic3x-hifi",
- .platform_name = "s6000-pcm-audio",
- .codec_name = "tlv320aic3x-codec.0-001a",
- .init = s6105_aic3x_init,
- .ops = &s6105_ops,
-};
-
-/* s6105 audio machine driver */
-static struct snd_soc_card snd_soc_card_s6105 = {
- .name = "Stretch IP Camera",
- .owner = THIS_MODULE,
- .dai_link = &s6105_dai,
- .num_links = 1,
-
- .dapm_widgets = aic3x_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(aic3x_dapm_widgets),
- .dapm_routes = audio_map,
- .num_dapm_routes = ARRAY_SIZE(audio_map),
- .fully_routed = true,
-};
-
-static struct s6000_snd_platform_data s6105_snd_data __initdata = {
- .wide = 0,
- .channel_in = 0,
- .channel_out = 1,
- .lines_in = 1,
- .lines_out = 1,
- .same_rate = 1,
-};
-
-static struct platform_device *s6105_snd_device;
-
-/* temporary i2c device creation until this can be moved into the machine
- * support file.
-*/
-static struct i2c_board_info i2c_device[] = {
- { I2C_BOARD_INFO("tlv320aic33", 0x18), }
-};
-
-static int __init s6105_init(void)
-{
- int ret;
-
- i2c_register_board_info(0, i2c_device, ARRAY_SIZE(i2c_device));
-
- s6105_snd_device = platform_device_alloc("soc-audio", -1);
- if (!s6105_snd_device)
- return -ENOMEM;
-
- platform_set_drvdata(s6105_snd_device, &snd_soc_card_s6105);
- platform_device_add_data(s6105_snd_device, &s6105_snd_data,
- sizeof(s6105_snd_data));
-
- ret = platform_device_add(s6105_snd_device);
- if (ret)
- platform_device_put(s6105_snd_device);
-
- return ret;
-}
-
-static void __exit s6105_exit(void)
-{
- platform_device_unregister(s6105_snd_device);
-}
-
-module_init(s6105_init);
-module_exit(s6105_exit);
-
-MODULE_AUTHOR("Daniel Gloeckner");
-MODULE_DESCRIPTION("Stretch s6105 IP camera ASoC driver");
-MODULE_LICENSE("GPL");
int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
{
+ int ret = hists__init();
+
+ if (ret < 0)
+ return ret;
+
perf_config(perf_default_config, NULL);
argc = parse_options(argc, argv, options, diff_usage, 0);
OPT_CALLBACK('x', "exec", NULL, "executable|path",
"target executable name or path", opt_set_target),
OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
- "Disable symbol demangling"),
+ "Enable symbol demangling"),
OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
"Enable kernel symbol demangling"),
OPT_END()
#define wmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
#define cpu_relax() asm volatile("rep; nop" ::: "memory");
-#define CPUINFO_PROC "model name"
+#define CPUINFO_PROC {"model name"}
#ifndef __NR_perf_event_open
# define __NR_perf_event_open 336
#endif
#define wmb() asm volatile("sfence" ::: "memory")
#define rmb() asm volatile("lfence" ::: "memory")
#define cpu_relax() asm volatile("rep; nop" ::: "memory");
-#define CPUINFO_PROC "model name"
+#define CPUINFO_PROC {"model name"}
#ifndef __NR_perf_event_open
# define __NR_perf_event_open 298
#endif
#define mb() asm volatile ("sync" ::: "memory")
#define wmb() asm volatile ("sync" ::: "memory")
#define rmb() asm volatile ("sync" ::: "memory")
-#define CPUINFO_PROC "cpu"
+#define CPUINFO_PROC {"cpu"}
#endif
#ifdef __s390__
#define mb() asm volatile("bcr 15,0" ::: "memory")
#define wmb() asm volatile("bcr 15,0" ::: "memory")
#define rmb() asm volatile("bcr 15,0" ::: "memory")
-#define CPUINFO_PROC "vendor_id"
+#define CPUINFO_PROC {"vendor_id"}
#endif
#ifdef __sh__
# define wmb() asm volatile("" ::: "memory")
# define rmb() asm volatile("" ::: "memory")
#endif
-#define CPUINFO_PROC "cpu type"
+#define CPUINFO_PROC {"cpu type"}
#endif
#ifdef __hppa__
#define mb() asm volatile("" ::: "memory")
#define wmb() asm volatile("" ::: "memory")
#define rmb() asm volatile("" ::: "memory")
-#define CPUINFO_PROC "cpu"
+#define CPUINFO_PROC {"cpu"}
#endif
#ifdef __sparc__
#endif
#define wmb() asm volatile("":::"memory")
#define rmb() asm volatile("":::"memory")
-#define CPUINFO_PROC "cpu"
+#define CPUINFO_PROC {"cpu"}
#endif
#ifdef __alpha__
#define mb() asm volatile("mb" ::: "memory")
#define wmb() asm volatile("wmb" ::: "memory")
#define rmb() asm volatile("mb" ::: "memory")
-#define CPUINFO_PROC "cpu model"
+#define CPUINFO_PROC {"cpu model"}
#endif
#ifdef __ia64__
#define wmb() asm volatile ("mf" ::: "memory")
#define rmb() asm volatile ("mf" ::: "memory")
#define cpu_relax() asm volatile ("hint @pause" ::: "memory")
-#define CPUINFO_PROC "model name"
+#define CPUINFO_PROC {"model name"}
#endif
#ifdef __arm__
#define mb() ((void(*)(void))0xffff0fa0)()
#define wmb() ((void(*)(void))0xffff0fa0)()
#define rmb() ((void(*)(void))0xffff0fa0)()
-#define CPUINFO_PROC "Processor"
+#define CPUINFO_PROC {"model name", "Processor"}
#endif
#ifdef __aarch64__
: "memory")
#define wmb() mb()
#define rmb() mb()
-#define CPUINFO_PROC "cpu model"
+#define CPUINFO_PROC {"cpu model"}
#endif
#ifdef __arc__
#define mb() asm volatile("" ::: "memory")
#define wmb() asm volatile("" ::: "memory")
#define rmb() asm volatile("" ::: "memory")
-#define CPUINFO_PROC "Processor"
+#define CPUINFO_PROC {"Processor"}
#endif
#ifdef __metag__
#define mb() asm volatile("" ::: "memory")
#define wmb() asm volatile("" ::: "memory")
#define rmb() asm volatile("" ::: "memory")
-#define CPUINFO_PROC "CPU"
+#define CPUINFO_PROC {"CPU"}
#endif
#ifdef __xtensa__
#define mb() asm volatile("memw" ::: "memory")
#define wmb() asm volatile("memw" ::: "memory")
#define rmb() asm volatile("" ::: "memory")
-#define CPUINFO_PROC "core ID"
+#define CPUINFO_PROC {"core ID"}
#endif
#ifdef __tile__
#define wmb() asm volatile ("mf" ::: "memory")
#define rmb() asm volatile ("mf" ::: "memory")
#define cpu_relax() asm volatile ("mfspr zero, PASS" ::: "memory")
-#define CPUINFO_PROC "model name"
+#define CPUINFO_PROC {"model name"}
#endif
#define barrier() asm volatile ("" ::: "memory")
return do_write_string(fd, perf_version_string);
}
-static int write_cpudesc(int fd, struct perf_header *h __maybe_unused,
- struct perf_evlist *evlist __maybe_unused)
+static int __write_cpudesc(int fd, const char *cpuinfo_proc)
{
-#ifndef CPUINFO_PROC
-#define CPUINFO_PROC NULL
-#endif
FILE *file;
char *buf = NULL;
char *s, *p;
- const char *search = CPUINFO_PROC;
+ const char *search = cpuinfo_proc;
size_t len = 0;
int ret = -1;
return ret;
}
+static int write_cpudesc(int fd, struct perf_header *h __maybe_unused,
+ struct perf_evlist *evlist __maybe_unused)
+{
+#ifndef CPUINFO_PROC
+#define CPUINFO_PROC {"model name", }
+#endif
+ const char *cpuinfo_procs[] = CPUINFO_PROC;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(cpuinfo_procs); i++) {
+ int ret;
+ ret = __write_cpudesc(fd, cpuinfo_procs[i]);
+ if (ret >= 0)
+ return ret;
+ }
+ return -1;
+}
+
+
static int write_nrcpus(int fd, struct perf_header *h __maybe_unused,
struct perf_evlist *evlist __maybe_unused)
{
static int64_t
sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
{
+ if (!left->branch_info || !right->branch_info)
+ return cmp_null(left->branch_info, right->branch_info);
+
return _sort__dso_cmp(left->branch_info->from.map,
right->branch_info->from.map);
}
static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width)
{
- return _hist_entry__dso_snprintf(he->branch_info->from.map,
- bf, size, width);
+ if (he->branch_info)
+ return _hist_entry__dso_snprintf(he->branch_info->from.map,
+ bf, size, width);
+ else
+ return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
}
static int64_t
sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
{
+ if (!left->branch_info || !right->branch_info)
+ return cmp_null(left->branch_info, right->branch_info);
+
return _sort__dso_cmp(left->branch_info->to.map,
right->branch_info->to.map);
}
static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width)
{
- return _hist_entry__dso_snprintf(he->branch_info->to.map,
- bf, size, width);
+ if (he->branch_info)
+ return _hist_entry__dso_snprintf(he->branch_info->to.map,
+ bf, size, width);
+ else
+ return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
}
static int64_t
struct addr_map_symbol *from_l = &left->branch_info->from;
struct addr_map_symbol *from_r = &right->branch_info->from;
+ if (!left->branch_info || !right->branch_info)
+ return cmp_null(left->branch_info, right->branch_info);
+
+ from_l = &left->branch_info->from;
+ from_r = &right->branch_info->from;
+
if (!from_l->sym && !from_r->sym)
return _sort__addr_cmp(from_l->addr, from_r->addr);
static int64_t
sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
{
- struct addr_map_symbol *to_l = &left->branch_info->to;
- struct addr_map_symbol *to_r = &right->branch_info->to;
+ struct addr_map_symbol *to_l, *to_r;
+
+ if (!left->branch_info || !right->branch_info)
+ return cmp_null(left->branch_info, right->branch_info);
+
+ to_l = &left->branch_info->to;
+ to_r = &right->branch_info->to;
if (!to_l->sym && !to_r->sym)
return _sort__addr_cmp(to_l->addr, to_r->addr);
static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width)
{
- struct addr_map_symbol *from = &he->branch_info->from;
- return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
- he->level, bf, size, width);
+ if (he->branch_info) {
+ struct addr_map_symbol *from = &he->branch_info->from;
+ return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
+ he->level, bf, size, width);
+ }
+
+ return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
}
static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width)
{
- struct addr_map_symbol *to = &he->branch_info->to;
- return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
- he->level, bf, size, width);
+ if (he->branch_info) {
+ struct addr_map_symbol *to = &he->branch_info->to;
+ return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
+ he->level, bf, size, width);
+ }
+
+ return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
}
struct sort_entry sort_dso_from = {
static int64_t
sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
{
- const unsigned char mp = left->branch_info->flags.mispred !=
- right->branch_info->flags.mispred;
- const unsigned char p = left->branch_info->flags.predicted !=
- right->branch_info->flags.predicted;
+ unsigned char mp, p;
+
+ if (!left->branch_info || !right->branch_info)
+ return cmp_null(left->branch_info, right->branch_info);
+ mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred;
+ p = left->branch_info->flags.predicted != right->branch_info->flags.predicted;
return mp || p;
}
size_t size, unsigned int width){
static const char *out = "N/A";
- if (he->branch_info->flags.predicted)
- out = "N";
- else if (he->branch_info->flags.mispred)
- out = "Y";
+ if (he->branch_info) {
+ if (he->branch_info->flags.predicted)
+ out = "N";
+ else if (he->branch_info->flags.mispred)
+ out = "Y";
+ }
return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
}
static int64_t
sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
{
+ if (!left->branch_info || !right->branch_info)
+ return cmp_null(left->branch_info, right->branch_info);
+
return left->branch_info->flags.abort !=
right->branch_info->flags.abort;
}
static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width)
{
- static const char *out = ".";
+ static const char *out = "N/A";
+
+ if (he->branch_info) {
+ if (he->branch_info->flags.abort)
+ out = "A";
+ else
+ out = ".";
+ }
- if (he->branch_info->flags.abort)
- out = "A";
return repsep_snprintf(bf, size, "%-*s", width, out);
}
static int64_t
sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
{
+ if (!left->branch_info || !right->branch_info)
+ return cmp_null(left->branch_info, right->branch_info);
+
return left->branch_info->flags.in_tx !=
right->branch_info->flags.in_tx;
}
static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width)
{
- static const char *out = ".";
+ static const char *out = "N/A";
- if (he->branch_info->flags.in_tx)
- out = "T";
+ if (he->branch_info) {
+ if (he->branch_info->flags.in_tx)
+ out = "T";
+ else
+ out = ".";
+ }
return repsep_snprintf(bf, size, "%-*s", width, out);
}
if (!new)
return -ENOMEM;
list_add(&new->list, &thread->comm_list);
+
+ if (exec)
+ unwind__flush_access(thread);
}
thread->comm_set = true;
return -ENOMEM;
}
+ unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL);
thread__set_priv(thread, addr_space);
return 0;
}
+void unwind__flush_access(struct thread *thread)
+{
+ unw_addr_space_t addr_space;
+
+ if (callchain_param.record_mode != CALLCHAIN_DWARF)
+ return;
+
+ addr_space = thread__priv(thread);
+ unw_flush_cache(addr_space, 0, 0);
+}
+
void unwind__finish_access(struct thread *thread)
{
unw_addr_space_t addr_space;
#ifdef HAVE_LIBUNWIND_SUPPORT
int libunwind__arch_reg_id(int regnum);
int unwind__prepare_access(struct thread *thread);
+void unwind__flush_access(struct thread *thread);
void unwind__finish_access(struct thread *thread);
#else
static inline int unwind__prepare_access(struct thread *thread __maybe_unused)
return 0;
}
+static inline void unwind__flush_access(struct thread *thread __maybe_unused) {}
static inline void unwind__finish_access(struct thread *thread __maybe_unused) {}
#endif
#else
return 0;
}
+static inline void unwind__flush_access(struct thread *thread __maybe_unused) {}
static inline void unwind__finish_access(struct thread *thread __maybe_unused) {}
#endif /* HAVE_DWARF_UNWIND_SUPPORT */
#endif /* __UNWIND_H */