mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 02:21:52 +09:00
Merge 6.1.110 into android14-6.1-lts
Changes in 6.1.110
sch/netem: fix use after free in netem_dequeue
ASoC: dapm: Fix UAF for snd_soc_pcm_runtime object
KVM: x86: Acquire kvm->srcu when handling KVM_SET_VCPU_EVENTS
KVM: SVM: fix emulation of msr reads/writes of MSR_FS_BASE and MSR_GS_BASE
KVM: SVM: Don't advertise Bus Lock Detect to guest if SVM support is missing
ALSA: hda/conexant: Add pincfg quirk to enable top speakers on Sirius devices
ALSA: hda/realtek: add patch for internal mic in Lenovo V145
ALSA: hda/realtek: Support mute LED on HP Laptop 14-dq2xxx
ksmbd: unset the binding mark of a reused connection
ksmbd: Unlock on in ksmbd_tcp_set_interfaces()
ata: libata: Fix memory leak for error path in ata_host_alloc()
x86/tdx: Fix data leak in mmio_read()
perf/x86/intel: Limit the period on Haswell
irqchip/gic-v2m: Fix refcount leak in gicv2m_of_init()
x86/kaslr: Expose and use the end of the physical memory address space
rtmutex: Drop rt_mutex::wait_lock before scheduling
nvme-pci: Add sleep quirk for Samsung 990 Evo
Revert "Bluetooth: MGMT/SMP: Fix address type when using SMP over BREDR/LE"
Bluetooth: MGMT: Ignore keys being loaded with invalid type
mmc: core: apply SD quirks earlier during probe
mmc: dw_mmc: Fix IDMAC operation with pages bigger than 4K
mmc: sdhci-of-aspeed: fix module autoloading
mmc: cqhci: Fix checking of CQHCI_HALT state
fuse: update stats for pages in dropped aux writeback list
fuse: use unsigned type for getxattr/listxattr size truncation
clk: qcom: clk-alpha-pll: Fix the pll post div mask
clk: qcom: clk-alpha-pll: Fix the trion pll postdiv set rate API
can: mcp251x: fix deadlock if an interrupt occurs during mcp251x_open
spi: rockchip: Resolve unbalanced runtime PM / system PM handling
tracing: Avoid possible softlockup in tracing_iter_reset()
net: mctp-serial: Fix missing escapes on transmit
x86/fpu: Avoid writing LBR bit to IA32_XSS unless supported
Revert "drm/amdgpu: align pp_power_profile_mode with kernel docs"
tcp_bpf: fix return value of tcp_bpf_sendmsg()
ila: call nf_unregister_net_hooks() sooner
sched: sch_cake: fix bulk flow accounting logic for host fairness
nilfs2: fix missing cleanup on rollforward recovery error
nilfs2: protect references to superblock parameters exposed in sysfs
nilfs2: fix state management in error path of log writing function
ALSA: control: Apply sanity check of input values for user elements
ALSA: hda: Add input value sanity checks to HDMI channel map controls
smack: unix sockets: fix accept()ed socket label
ELF: fix kernel.randomize_va_space double read
irqchip/armada-370-xp: Do not allow mapping IRQ 0 and 1
af_unix: Remove put_pid()/put_cred() in copy_peercred().
x86/kmsan: Fix hook for unaligned accesses
iommu: sun50i: clear bypass register
netfilter: nf_conncount: fix wrong variable type
udf: Avoid excessive partition lengths
fs/ntfs3: One more reason to mark inode bad
media: vivid: fix wrong sizeimage value for mplane
leds: spi-byte: Call of_node_put() on error path
wifi: brcmsmac: advertise MFP_CAPABLE to enable WPA3
usb: uas: set host status byte on data completion error
usb: gadget: aspeed_udc: validate endpoint index for ast udc
drm/amd/display: Check HDCP returned status
drm/amdgpu: Fix smatch static checker warning
drm/amdgpu: clear RB_OVERFLOW bit when enabling interrupts
media: vivid: don't set HDMI TX controls if there are no HDMI outputs
PCI: keystone: Add workaround for Errata #i2037 (AM65x SR 1.0)
Input: ili210x - use kvmalloc() to allocate buffer for firmware update
media: qcom: camss: Add check for v4l2_fwnode_endpoint_parse
pcmcia: Use resource_size function on resource object
drm/amd/display: Check denominator pbn_div before used
drm/amdgpu: check for LINEAR_ALIGNED correctly in check_tiling_flags_gfx6
can: bcm: Remove proc entry when dev is unregistered.
can: m_can: Release irq on error in m_can_open
can: mcp251xfd: fix ring configuration when switching from CAN-CC to CAN-FD mode
rust: Use awk instead of recent xargs
rust: kbuild: fix export of bss symbols
cifs: Fix FALLOC_FL_ZERO_RANGE to preflush buffered part of target region
igb: Fix not clearing TimeSync interrupts for 82580
ice: Add netif_device_attach/detach into PF reset flow
platform/x86: dell-smbios: Fix error path in dell_smbios_init()
regulator: Add of_regulator_bulk_get_all
regulator: core: Stub devm_regulator_bulk_get_const() if !CONFIG_REGULATOR
igc: Unlock on error in igc_io_resume()
ice: Use ice_max_xdp_frame_size() in ice_xdp_setup_prog()
ice: allow hot-swapping XDP programs
ice: do not bring the VSI up, if it was down before the XDP setup
usbnet: modern method to get random MAC
bareudp: Fix device stats updates.
fou: Fix null-ptr-deref in GRO.
net: bridge: br_fdb_external_learn_add(): always set EXT_LEARN
net: dsa: vsc73xx: fix possible subblocks range of CAPT block
firmware: cs_dsp: Don't allow writes to read-only controls
phy: zynqmp: Take the phy mutex in xlate
ASoC: topology: Properly initialize soc_enum values
dm init: Handle minors larger than 255
iommu/vt-d: Handle volatile descriptor status read
cgroup: Protect css->cgroup write under css_set_lock
um: line: always fill *error_out in setup_one_line()
devres: Initialize an uninitialized struct member
pci/hotplug/pnv_php: Fix hotplug driver crash on Powernv
crypto: qat - fix unintentional re-enabling of error interrupts
hwmon: (adc128d818) Fix underflows seen when writing limit attributes
hwmon: (lm95234) Fix underflows seen when writing limit attributes
hwmon: (nct6775-core) Fix underflows seen when writing limit attributes
hwmon: (w83627ehf) Fix underflows seen when writing limit attributes
libbpf: Add NULL checks to bpf_object__{prev_map,next_map}
drm/amdgpu: Set no_hw_access when VF request full GPU fails
ext4: fix possible tid_t sequence overflows
dma-mapping: benchmark: Don't starve others when doing the test
wifi: mwifiex: Do not return unused priv in mwifiex_get_priv_by_id()
smp: Add missing destroy_work_on_stack() call in smp_call_on_cpu()
fs/ntfs3: Check more cases when directory is corrupted
btrfs: replace BUG_ON with ASSERT in walk_down_proc()
btrfs: clean up our handling of refs == 0 in snapshot delete
btrfs: replace BUG_ON() with error handling at update_ref_for_cow()
riscv: set trap vector earlier
PCI: Add missing bridge lock to pci_bus_lock()
tcp: Don't drop SYN+ACK for simultaneous connect().
net: dpaa: avoid on-stack arrays of NR_CPUS elements
i3c: mipi-i3c-hci: Error out instead on BUG_ON() in IBI DMA setup
kselftests: dmabuf-heaps: Ensure the driver name is null-terminated
btrfs: initialize location to fix -Wmaybe-uninitialized in btrfs_lookup_dentry()
s390/vmlinux.lds.S: Move ro_after_init section behind rodata section
HID: cougar: fix slab-out-of-bounds Read in cougar_report_fixup
HID: amd_sfh: free driver_data after destroying hid device
Input: uinput - reject requests with unreasonable number of slots
usbnet: ipheth: race between ipheth_close and error handling
Squashfs: sanity check symbolic link size
of/irq: Prevent device address out-of-bounds read in interrupt map walk
lib/generic-radix-tree.c: Fix rare race in __genradix_ptr_alloc()
MIPS: cevt-r4k: Don't call get_c0_compare_int if timer irq is installed
ata: pata_macio: Use WARN instead of BUG
NFSv4: Add missing rescheduling points in nfs_client_return_marked_delegations
selftests: mptcp: fix backport issues
selftests: mptcp: join: validate event numbers
selftests: mptcp: join: check re-re-adding ID 0 signal
io_uring/io-wq: stop setting PF_NO_SETAFFINITY on io-wq workers
io_uring/sqpoll: Do not set PF_NO_SETAFFINITY on sqpoll threads
tcp: process the 3rd ACK with sk_socket for TFO/MPTCP
staging: iio: frequency: ad9834: Validate frequency parameter value
iio: buffer-dmaengine: fix releasing dma channel on error
iio: fix scale application in iio_convert_raw_to_processed_unlocked
iio: adc: ad7124: fix config comparison
iio: adc: ad7606: remove frstdata check for serial mode
iio: adc: ad7124: fix chip ID mismatch
usb: dwc3: core: update LC timer as per USB Spec V3.2
binder: fix UAF caused by offsets overwrite
nvmem: Fix return type of devm_nvmem_device_get() in kerneldoc
uio_hv_generic: Fix kernel NULL pointer dereference in hv_uio_rescind
Drivers: hv: vmbus: Fix rescind handling in uio_hv_generic
VMCI: Fix use-after-free when removing resource in vmci_resource_remove()
clocksource/drivers/imx-tpm: Fix return -ETIME when delta exceeds INT_MAX
clocksource/drivers/imx-tpm: Fix next event not taking effect sometime
clocksource/drivers/timer-of: Remove percpu irq related code
uprobes: Use kzalloc to allocate xol area
perf/aux: Fix AUX buffer serialization
fuse: add "expire only" mode to FUSE_NOTIFY_INVAL_ENTRY
fuse: allow non-extending parallel direct writes on the same file
fuse: add request extension
fuse: fix memory leak in fuse_create_open
net: mana: Fix error handling in mana_create_txq/rxq's NAPI cleanup
workqueue: wq_watchdog_touch is always called with valid CPU
workqueue: Improve scalability of workqueue watchdog touch
ACPI: processor: Return an error if acpi_processor_get_info() fails in processor_add()
ACPI: processor: Fix memory leaks in error paths of processor_add()
arm64: acpi: Move get_cpu_for_acpi_id() to a header
arm64: acpi: Harden get_cpu_for_acpi_id() against missing CPU entry
can: mcp251xfd: mcp251xfd_handle_rxif_ring_uinc(): factor out in separate function
can: mcp251xfd: rx: prepare to workaround broken RX FIFO head index erratum
can: mcp251xfd: clarify the meaning of timestamp
can: mcp251xfd: rx: add workaround for erratum DS80000789E 6 of mcp2518fd
drm/amd: Add gfx12 swizzle mode defs
drm/amdgpu: handle gfx12 in amdgpu_display_verify_sizes
powerpc/64e: remove unused IBM HTW code
powerpc/64e: split out nohash Book3E 64-bit code
powerpc/64e: Define mmu_pte_psize static
ASoC: tegra: Fix CBB error during probe()
nvmet-tcp: fix kernel crash if commands allocation fails
ASoc: SOF: topology: Clear SOF link platform name upon unload
ASoC: sunxi: sun4i-i2s: fix LRCLK polarity in i2s mode
drm/i915/fence: Mark debug_fence_init_onstack() with __maybe_unused
drm/i915/fence: Mark debug_fence_free() with __maybe_unused
gpio: rockchip: fix OF node leak in probe()
gpio: modepin: Enable module autoloading
ublk_drv: fix NULL pointer dereference in ublk_ctrl_start_recovery()
x86/mm: Fix PTI for i386 some more
btrfs: fix race between direct IO write and fsync when using same fd
bpf: Silence a warning in btf_type_id_size()
memcg: protect concurrent access to mem_cgroup_idr
regulator: of: fix a NULL vs IS_ERR() check in of_regulator_bulk_get_all()
fuse: add feature flag for expire-only
Linux 6.1.110
Change-Id: I58340d95835bd9cb4da4dd8ce1d0e49c5070ea2e
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
2
Makefile
2
Makefile
@@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
VERSION = 6
|
||||
PATCHLEVEL = 1
|
||||
SUBLEVEL = 109
|
||||
SUBLEVEL = 110
|
||||
EXTRAVERSION =
|
||||
NAME = Curry Ramen
|
||||
|
||||
|
||||
@@ -97,6 +97,18 @@ static inline u32 get_acpi_id_for_cpu(unsigned int cpu)
|
||||
return acpi_cpu_get_madt_gicc(cpu)->uid;
|
||||
}
|
||||
|
||||
static inline int get_cpu_for_acpi_id(u32 uid)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
for (cpu = 0; cpu < nr_cpu_ids; cpu++)
|
||||
if (acpi_cpu_get_madt_gicc(cpu) &&
|
||||
uid == get_acpi_id_for_cpu(cpu))
|
||||
return cpu;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline void arch_fix_phys_package_id(int num, u32 slot) { }
|
||||
void __init acpi_init_cpus(void);
|
||||
int apei_claim_sea(struct pt_regs *regs);
|
||||
|
||||
@@ -34,17 +34,6 @@ int __init acpi_numa_get_nid(unsigned int cpu)
|
||||
return acpi_early_node_map[cpu];
|
||||
}
|
||||
|
||||
static inline int get_cpu_for_acpi_id(u32 uid)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
for (cpu = 0; cpu < nr_cpu_ids; cpu++)
|
||||
if (uid == get_acpi_id_for_cpu(cpu))
|
||||
return cpu;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int __init acpi_parse_gicc_pxm(union acpi_subtable_headers *header,
|
||||
const unsigned long end)
|
||||
{
|
||||
|
||||
@@ -303,8 +303,7 @@ extern unsigned long linear_map_top;
|
||||
extern int book3e_htw_mode;
|
||||
|
||||
#define PPC_HTW_NONE 0
|
||||
#define PPC_HTW_IBM 1
|
||||
#define PPC_HTW_E6500 2
|
||||
#define PPC_HTW_E6500 1
|
||||
|
||||
/*
|
||||
* 64-bit booke platforms don't load the tlb in the tlb miss handler code.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC)
|
||||
|
||||
obj-y += mmu_context.o tlb.o tlb_low.o kup.o
|
||||
obj-$(CONFIG_PPC_BOOK3E_64) += tlb_low_64e.o book3e_pgtable.o
|
||||
obj-$(CONFIG_PPC_BOOK3E_64) += tlb_64e.o tlb_low_64e.o book3e_pgtable.o
|
||||
obj-$(CONFIG_40x) += 40x.o
|
||||
obj-$(CONFIG_44x) += 44x.o
|
||||
obj-$(CONFIG_PPC_8xx) += 8xx.o
|
||||
|
||||
@@ -110,28 +110,6 @@ struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = {
|
||||
};
|
||||
#endif
|
||||
|
||||
/* The variables below are currently only used on 64-bit Book3E
|
||||
* though this will probably be made common with other nohash
|
||||
* implementations at some point
|
||||
*/
|
||||
#ifdef CONFIG_PPC64
|
||||
|
||||
int mmu_pte_psize; /* Page size used for PTE pages */
|
||||
int mmu_vmemmap_psize; /* Page size used for the virtual mem map */
|
||||
int book3e_htw_mode; /* HW tablewalk? Value is PPC_HTW_* */
|
||||
unsigned long linear_map_top; /* Top of linear mapping */
|
||||
|
||||
|
||||
/*
|
||||
* Number of bytes to add to SPRN_SPRG_TLB_EXFRAME on crit/mcheck/debug
|
||||
* exceptions. This is used for bolted and e6500 TLB miss handlers which
|
||||
* do not modify this SPRG in the TLB miss code; for other TLB miss handlers,
|
||||
* this is set to zero.
|
||||
*/
|
||||
int extlb_level_exc;
|
||||
|
||||
#endif /* CONFIG_PPC64 */
|
||||
|
||||
#ifdef CONFIG_PPC_E500
|
||||
/* next_tlbcam_idx is used to round-robin tlbcam entry assignment */
|
||||
DEFINE_PER_CPU(int, next_tlbcam_idx);
|
||||
@@ -361,381 +339,7 @@ void tlb_flush(struct mmu_gather *tlb)
|
||||
flush_tlb_mm(tlb->mm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Below are functions specific to the 64-bit variant of Book3E though that
|
||||
* may change in the future
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_PPC64
|
||||
|
||||
/*
|
||||
* Handling of virtual linear page tables or indirect TLB entries
|
||||
* flushing when PTE pages are freed
|
||||
*/
|
||||
void tlb_flush_pgtable(struct mmu_gather *tlb, unsigned long address)
|
||||
{
|
||||
int tsize = mmu_psize_defs[mmu_pte_psize].enc;
|
||||
|
||||
if (book3e_htw_mode != PPC_HTW_NONE) {
|
||||
unsigned long start = address & PMD_MASK;
|
||||
unsigned long end = address + PMD_SIZE;
|
||||
unsigned long size = 1UL << mmu_psize_defs[mmu_pte_psize].shift;
|
||||
|
||||
/* This isn't the most optimal, ideally we would factor out the
|
||||
* while preempt & CPU mask mucking around, or even the IPI but
|
||||
* it will do for now
|
||||
*/
|
||||
while (start < end) {
|
||||
__flush_tlb_page(tlb->mm, start, tsize, 1);
|
||||
start += size;
|
||||
}
|
||||
} else {
|
||||
unsigned long rmask = 0xf000000000000000ul;
|
||||
unsigned long rid = (address & rmask) | 0x1000000000000000ul;
|
||||
unsigned long vpte = address & ~rmask;
|
||||
|
||||
vpte = (vpte >> (PAGE_SHIFT - 3)) & ~0xffful;
|
||||
vpte |= rid;
|
||||
__flush_tlb_page(tlb->mm, vpte, tsize, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void __init setup_page_sizes(void)
|
||||
{
|
||||
unsigned int tlb0cfg;
|
||||
unsigned int tlb0ps;
|
||||
unsigned int eptcfg;
|
||||
int i, psize;
|
||||
|
||||
#ifdef CONFIG_PPC_E500
|
||||
unsigned int mmucfg = mfspr(SPRN_MMUCFG);
|
||||
int fsl_mmu = mmu_has_feature(MMU_FTR_TYPE_FSL_E);
|
||||
|
||||
if (fsl_mmu && (mmucfg & MMUCFG_MAVN) == MMUCFG_MAVN_V1) {
|
||||
unsigned int tlb1cfg = mfspr(SPRN_TLB1CFG);
|
||||
unsigned int min_pg, max_pg;
|
||||
|
||||
min_pg = (tlb1cfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT;
|
||||
max_pg = (tlb1cfg & TLBnCFG_MAXSIZE) >> TLBnCFG_MAXSIZE_SHIFT;
|
||||
|
||||
for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
|
||||
struct mmu_psize_def *def;
|
||||
unsigned int shift;
|
||||
|
||||
def = &mmu_psize_defs[psize];
|
||||
shift = def->shift;
|
||||
|
||||
if (shift == 0 || shift & 1)
|
||||
continue;
|
||||
|
||||
/* adjust to be in terms of 4^shift Kb */
|
||||
shift = (shift - 10) >> 1;
|
||||
|
||||
if ((shift >= min_pg) && (shift <= max_pg))
|
||||
def->flags |= MMU_PAGE_SIZE_DIRECT;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fsl_mmu && (mmucfg & MMUCFG_MAVN) == MMUCFG_MAVN_V2) {
|
||||
u32 tlb1cfg, tlb1ps;
|
||||
|
||||
tlb0cfg = mfspr(SPRN_TLB0CFG);
|
||||
tlb1cfg = mfspr(SPRN_TLB1CFG);
|
||||
tlb1ps = mfspr(SPRN_TLB1PS);
|
||||
eptcfg = mfspr(SPRN_EPTCFG);
|
||||
|
||||
if ((tlb1cfg & TLBnCFG_IND) && (tlb0cfg & TLBnCFG_PT))
|
||||
book3e_htw_mode = PPC_HTW_E6500;
|
||||
|
||||
/*
|
||||
* We expect 4K subpage size and unrestricted indirect size.
|
||||
* The lack of a restriction on indirect size is a Freescale
|
||||
* extension, indicated by PSn = 0 but SPSn != 0.
|
||||
*/
|
||||
if (eptcfg != 2)
|
||||
book3e_htw_mode = PPC_HTW_NONE;
|
||||
|
||||
for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
|
||||
struct mmu_psize_def *def = &mmu_psize_defs[psize];
|
||||
|
||||
if (!def->shift)
|
||||
continue;
|
||||
|
||||
if (tlb1ps & (1U << (def->shift - 10))) {
|
||||
def->flags |= MMU_PAGE_SIZE_DIRECT;
|
||||
|
||||
if (book3e_htw_mode && psize == MMU_PAGE_2M)
|
||||
def->flags |= MMU_PAGE_SIZE_INDIRECT;
|
||||
}
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
tlb0cfg = mfspr(SPRN_TLB0CFG);
|
||||
tlb0ps = mfspr(SPRN_TLB0PS);
|
||||
eptcfg = mfspr(SPRN_EPTCFG);
|
||||
|
||||
/* Look for supported direct sizes */
|
||||
for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
|
||||
struct mmu_psize_def *def = &mmu_psize_defs[psize];
|
||||
|
||||
if (tlb0ps & (1U << (def->shift - 10)))
|
||||
def->flags |= MMU_PAGE_SIZE_DIRECT;
|
||||
}
|
||||
|
||||
/* Indirect page sizes supported ? */
|
||||
if ((tlb0cfg & TLBnCFG_IND) == 0 ||
|
||||
(tlb0cfg & TLBnCFG_PT) == 0)
|
||||
goto out;
|
||||
|
||||
book3e_htw_mode = PPC_HTW_IBM;
|
||||
|
||||
/* Now, we only deal with one IND page size for each
|
||||
* direct size. Hopefully all implementations today are
|
||||
* unambiguous, but we might want to be careful in the
|
||||
* future.
|
||||
*/
|
||||
for (i = 0; i < 3; i++) {
|
||||
unsigned int ps, sps;
|
||||
|
||||
sps = eptcfg & 0x1f;
|
||||
eptcfg >>= 5;
|
||||
ps = eptcfg & 0x1f;
|
||||
eptcfg >>= 5;
|
||||
if (!ps || !sps)
|
||||
continue;
|
||||
for (psize = 0; psize < MMU_PAGE_COUNT; psize++) {
|
||||
struct mmu_psize_def *def = &mmu_psize_defs[psize];
|
||||
|
||||
if (ps == (def->shift - 10))
|
||||
def->flags |= MMU_PAGE_SIZE_INDIRECT;
|
||||
if (sps == (def->shift - 10))
|
||||
def->ind = ps + 10;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
/* Cleanup array and print summary */
|
||||
pr_info("MMU: Supported page sizes\n");
|
||||
for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
|
||||
struct mmu_psize_def *def = &mmu_psize_defs[psize];
|
||||
const char *__page_type_names[] = {
|
||||
"unsupported",
|
||||
"direct",
|
||||
"indirect",
|
||||
"direct & indirect"
|
||||
};
|
||||
if (def->flags == 0) {
|
||||
def->shift = 0;
|
||||
continue;
|
||||
}
|
||||
pr_info(" %8ld KB as %s\n", 1ul << (def->shift - 10),
|
||||
__page_type_names[def->flags & 0x3]);
|
||||
}
|
||||
}
|
||||
|
||||
static void __init setup_mmu_htw(void)
|
||||
{
|
||||
/*
|
||||
* If we want to use HW tablewalk, enable it by patching the TLB miss
|
||||
* handlers to branch to the one dedicated to it.
|
||||
*/
|
||||
|
||||
switch (book3e_htw_mode) {
|
||||
case PPC_HTW_IBM:
|
||||
patch_exception(0x1c0, exc_data_tlb_miss_htw_book3e);
|
||||
patch_exception(0x1e0, exc_instruction_tlb_miss_htw_book3e);
|
||||
break;
|
||||
#ifdef CONFIG_PPC_E500
|
||||
case PPC_HTW_E6500:
|
||||
extlb_level_exc = EX_TLB_SIZE;
|
||||
patch_exception(0x1c0, exc_data_tlb_miss_e6500_book3e);
|
||||
patch_exception(0x1e0, exc_instruction_tlb_miss_e6500_book3e);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
pr_info("MMU: Book3E HW tablewalk %s\n",
|
||||
book3e_htw_mode != PPC_HTW_NONE ? "enabled" : "not supported");
|
||||
}
|
||||
|
||||
/*
|
||||
* Early initialization of the MMU TLB code
|
||||
*/
|
||||
static void early_init_this_mmu(void)
|
||||
{
|
||||
unsigned int mas4;
|
||||
|
||||
/* Set MAS4 based on page table setting */
|
||||
|
||||
mas4 = 0x4 << MAS4_WIMGED_SHIFT;
|
||||
switch (book3e_htw_mode) {
|
||||
case PPC_HTW_E6500:
|
||||
mas4 |= MAS4_INDD;
|
||||
mas4 |= BOOK3E_PAGESZ_2M << MAS4_TSIZED_SHIFT;
|
||||
mas4 |= MAS4_TLBSELD(1);
|
||||
mmu_pte_psize = MMU_PAGE_2M;
|
||||
break;
|
||||
|
||||
case PPC_HTW_IBM:
|
||||
mas4 |= MAS4_INDD;
|
||||
mas4 |= BOOK3E_PAGESZ_1M << MAS4_TSIZED_SHIFT;
|
||||
mmu_pte_psize = MMU_PAGE_1M;
|
||||
break;
|
||||
|
||||
case PPC_HTW_NONE:
|
||||
mas4 |= BOOK3E_PAGESZ_4K << MAS4_TSIZED_SHIFT;
|
||||
mmu_pte_psize = mmu_virtual_psize;
|
||||
break;
|
||||
}
|
||||
mtspr(SPRN_MAS4, mas4);
|
||||
|
||||
#ifdef CONFIG_PPC_E500
|
||||
if (mmu_has_feature(MMU_FTR_TYPE_FSL_E)) {
|
||||
unsigned int num_cams;
|
||||
bool map = true;
|
||||
|
||||
/* use a quarter of the TLBCAM for bolted linear map */
|
||||
num_cams = (mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY) / 4;
|
||||
|
||||
/*
|
||||
* Only do the mapping once per core, or else the
|
||||
* transient mapping would cause problems.
|
||||
*/
|
||||
#ifdef CONFIG_SMP
|
||||
if (hweight32(get_tensr()) > 1)
|
||||
map = false;
|
||||
#endif
|
||||
|
||||
if (map)
|
||||
linear_map_top = map_mem_in_cams(linear_map_top,
|
||||
num_cams, false, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* A sync won't hurt us after mucking around with
|
||||
* the MMU configuration
|
||||
*/
|
||||
mb();
|
||||
}
|
||||
|
||||
static void __init early_init_mmu_global(void)
|
||||
{
|
||||
/* XXX This should be decided at runtime based on supported
|
||||
* page sizes in the TLB, but for now let's assume 16M is
|
||||
* always there and a good fit (which it probably is)
|
||||
*
|
||||
* Freescale booke only supports 4K pages in TLB0, so use that.
|
||||
*/
|
||||
if (mmu_has_feature(MMU_FTR_TYPE_FSL_E))
|
||||
mmu_vmemmap_psize = MMU_PAGE_4K;
|
||||
else
|
||||
mmu_vmemmap_psize = MMU_PAGE_16M;
|
||||
|
||||
/* XXX This code only checks for TLB 0 capabilities and doesn't
|
||||
* check what page size combos are supported by the HW. It
|
||||
* also doesn't handle the case where a separate array holds
|
||||
* the IND entries from the array loaded by the PT.
|
||||
*/
|
||||
/* Look for supported page sizes */
|
||||
setup_page_sizes();
|
||||
|
||||
/* Look for HW tablewalk support */
|
||||
setup_mmu_htw();
|
||||
|
||||
#ifdef CONFIG_PPC_E500
|
||||
if (mmu_has_feature(MMU_FTR_TYPE_FSL_E)) {
|
||||
if (book3e_htw_mode == PPC_HTW_NONE) {
|
||||
extlb_level_exc = EX_TLB_SIZE;
|
||||
patch_exception(0x1c0, exc_data_tlb_miss_bolted_book3e);
|
||||
patch_exception(0x1e0,
|
||||
exc_instruction_tlb_miss_bolted_book3e);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set the global containing the top of the linear mapping
|
||||
* for use by the TLB miss code
|
||||
*/
|
||||
linear_map_top = memblock_end_of_DRAM();
|
||||
|
||||
ioremap_bot = IOREMAP_BASE;
|
||||
}
|
||||
|
||||
static void __init early_mmu_set_memory_limit(void)
|
||||
{
|
||||
#ifdef CONFIG_PPC_E500
|
||||
if (mmu_has_feature(MMU_FTR_TYPE_FSL_E)) {
|
||||
/*
|
||||
* Limit memory so we dont have linear faults.
|
||||
* Unlike memblock_set_current_limit, which limits
|
||||
* memory available during early boot, this permanently
|
||||
* reduces the memory available to Linux. We need to
|
||||
* do this because highmem is not supported on 64-bit.
|
||||
*/
|
||||
memblock_enforce_memory_limit(linear_map_top);
|
||||
}
|
||||
#endif
|
||||
|
||||
memblock_set_current_limit(linear_map_top);
|
||||
}
|
||||
|
||||
/* boot cpu only */
|
||||
void __init early_init_mmu(void)
|
||||
{
|
||||
early_init_mmu_global();
|
||||
early_init_this_mmu();
|
||||
early_mmu_set_memory_limit();
|
||||
}
|
||||
|
||||
void early_init_mmu_secondary(void)
|
||||
{
|
||||
early_init_this_mmu();
|
||||
}
|
||||
|
||||
void setup_initial_memory_limit(phys_addr_t first_memblock_base,
|
||||
phys_addr_t first_memblock_size)
|
||||
{
|
||||
/* On non-FSL Embedded 64-bit, we adjust the RMA size to match
|
||||
* the bolted TLB entry. We know for now that only 1G
|
||||
* entries are supported though that may eventually
|
||||
* change.
|
||||
*
|
||||
* on FSL Embedded 64-bit, usually all RAM is bolted, but with
|
||||
* unusual memory sizes it's possible for some RAM to not be mapped
|
||||
* (such RAM is not used at all by Linux, since we don't support
|
||||
* highmem on 64-bit). We limit ppc64_rma_size to what would be
|
||||
* mappable if this memblock is the only one. Additional memblocks
|
||||
* can only increase, not decrease, the amount that ends up getting
|
||||
* mapped. We still limit max to 1G even if we'll eventually map
|
||||
* more. This is due to what the early init code is set up to do.
|
||||
*
|
||||
* We crop it to the size of the first MEMBLOCK to
|
||||
* avoid going over total available memory just in case...
|
||||
*/
|
||||
#ifdef CONFIG_PPC_E500
|
||||
if (early_mmu_has_feature(MMU_FTR_TYPE_FSL_E)) {
|
||||
unsigned long linear_sz;
|
||||
unsigned int num_cams;
|
||||
|
||||
/* use a quarter of the TLBCAM for bolted linear map */
|
||||
num_cams = (mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY) / 4;
|
||||
|
||||
linear_sz = map_mem_in_cams(first_memblock_size, num_cams,
|
||||
true, true);
|
||||
|
||||
ppc64_rma_size = min_t(u64, linear_sz, 0x40000000);
|
||||
} else
|
||||
#endif
|
||||
ppc64_rma_size = min_t(u64, first_memblock_size, 0x40000000);
|
||||
|
||||
/* Finally limit subsequent allocations */
|
||||
memblock_set_current_limit(first_memblock_base + ppc64_rma_size);
|
||||
}
|
||||
#else /* ! CONFIG_PPC64 */
|
||||
#ifndef CONFIG_PPC64
|
||||
void __init early_init_mmu(void)
|
||||
{
|
||||
#ifdef CONFIG_PPC_47x
|
||||
|
||||
361
arch/powerpc/mm/nohash/tlb_64e.c
Normal file
361
arch/powerpc/mm/nohash/tlb_64e.c
Normal file
@@ -0,0 +1,361 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright 2008,2009 Ben Herrenschmidt <benh@kernel.crashing.org>
|
||||
* IBM Corp.
|
||||
*
|
||||
* Derived from arch/ppc/mm/init.c:
|
||||
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
|
||||
*
|
||||
* Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
|
||||
* and Cort Dougan (PReP) (cort@cs.nmt.edu)
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
*
|
||||
* Derived from "arch/i386/mm/init.c"
|
||||
* Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/memblock.h>
|
||||
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/tlb.h>
|
||||
#include <asm/code-patching.h>
|
||||
#include <asm/cputhreads.h>
|
||||
|
||||
#include <mm/mmu_decl.h>
|
||||
|
||||
/* The variables below are currently only used on 64-bit Book3E
|
||||
* though this will probably be made common with other nohash
|
||||
* implementations at some point
|
||||
*/
|
||||
static int mmu_pte_psize; /* Page size used for PTE pages */
|
||||
int mmu_vmemmap_psize; /* Page size used for the virtual mem map */
|
||||
int book3e_htw_mode; /* HW tablewalk? Value is PPC_HTW_* */
|
||||
unsigned long linear_map_top; /* Top of linear mapping */
|
||||
|
||||
|
||||
/*
|
||||
* Number of bytes to add to SPRN_SPRG_TLB_EXFRAME on crit/mcheck/debug
|
||||
* exceptions. This is used for bolted and e6500 TLB miss handlers which
|
||||
* do not modify this SPRG in the TLB miss code; for other TLB miss handlers,
|
||||
* this is set to zero.
|
||||
*/
|
||||
int extlb_level_exc;
|
||||
|
||||
/*
|
||||
* Handling of virtual linear page tables or indirect TLB entries
|
||||
* flushing when PTE pages are freed
|
||||
*/
|
||||
void tlb_flush_pgtable(struct mmu_gather *tlb, unsigned long address)
|
||||
{
|
||||
int tsize = mmu_psize_defs[mmu_pte_psize].enc;
|
||||
|
||||
if (book3e_htw_mode != PPC_HTW_NONE) {
|
||||
unsigned long start = address & PMD_MASK;
|
||||
unsigned long end = address + PMD_SIZE;
|
||||
unsigned long size = 1UL << mmu_psize_defs[mmu_pte_psize].shift;
|
||||
|
||||
/* This isn't the most optimal, ideally we would factor out the
|
||||
* while preempt & CPU mask mucking around, or even the IPI but
|
||||
* it will do for now
|
||||
*/
|
||||
while (start < end) {
|
||||
__flush_tlb_page(tlb->mm, start, tsize, 1);
|
||||
start += size;
|
||||
}
|
||||
} else {
|
||||
unsigned long rmask = 0xf000000000000000ul;
|
||||
unsigned long rid = (address & rmask) | 0x1000000000000000ul;
|
||||
unsigned long vpte = address & ~rmask;
|
||||
|
||||
vpte = (vpte >> (PAGE_SHIFT - 3)) & ~0xffful;
|
||||
vpte |= rid;
|
||||
__flush_tlb_page(tlb->mm, vpte, tsize, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void __init setup_page_sizes(void)
|
||||
{
|
||||
unsigned int tlb0cfg;
|
||||
unsigned int eptcfg;
|
||||
int psize;
|
||||
|
||||
#ifdef CONFIG_PPC_E500
|
||||
unsigned int mmucfg = mfspr(SPRN_MMUCFG);
|
||||
int fsl_mmu = mmu_has_feature(MMU_FTR_TYPE_FSL_E);
|
||||
|
||||
if (fsl_mmu && (mmucfg & MMUCFG_MAVN) == MMUCFG_MAVN_V1) {
|
||||
unsigned int tlb1cfg = mfspr(SPRN_TLB1CFG);
|
||||
unsigned int min_pg, max_pg;
|
||||
|
||||
min_pg = (tlb1cfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT;
|
||||
max_pg = (tlb1cfg & TLBnCFG_MAXSIZE) >> TLBnCFG_MAXSIZE_SHIFT;
|
||||
|
||||
for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
|
||||
struct mmu_psize_def *def;
|
||||
unsigned int shift;
|
||||
|
||||
def = &mmu_psize_defs[psize];
|
||||
shift = def->shift;
|
||||
|
||||
if (shift == 0 || shift & 1)
|
||||
continue;
|
||||
|
||||
/* adjust to be in terms of 4^shift Kb */
|
||||
shift = (shift - 10) >> 1;
|
||||
|
||||
if ((shift >= min_pg) && (shift <= max_pg))
|
||||
def->flags |= MMU_PAGE_SIZE_DIRECT;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fsl_mmu && (mmucfg & MMUCFG_MAVN) == MMUCFG_MAVN_V2) {
|
||||
u32 tlb1cfg, tlb1ps;
|
||||
|
||||
tlb0cfg = mfspr(SPRN_TLB0CFG);
|
||||
tlb1cfg = mfspr(SPRN_TLB1CFG);
|
||||
tlb1ps = mfspr(SPRN_TLB1PS);
|
||||
eptcfg = mfspr(SPRN_EPTCFG);
|
||||
|
||||
if ((tlb1cfg & TLBnCFG_IND) && (tlb0cfg & TLBnCFG_PT))
|
||||
book3e_htw_mode = PPC_HTW_E6500;
|
||||
|
||||
/*
|
||||
* We expect 4K subpage size and unrestricted indirect size.
|
||||
* The lack of a restriction on indirect size is a Freescale
|
||||
* extension, indicated by PSn = 0 but SPSn != 0.
|
||||
*/
|
||||
if (eptcfg != 2)
|
||||
book3e_htw_mode = PPC_HTW_NONE;
|
||||
|
||||
for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
|
||||
struct mmu_psize_def *def = &mmu_psize_defs[psize];
|
||||
|
||||
if (!def->shift)
|
||||
continue;
|
||||
|
||||
if (tlb1ps & (1U << (def->shift - 10))) {
|
||||
def->flags |= MMU_PAGE_SIZE_DIRECT;
|
||||
|
||||
if (book3e_htw_mode && psize == MMU_PAGE_2M)
|
||||
def->flags |= MMU_PAGE_SIZE_INDIRECT;
|
||||
}
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
out:
|
||||
/* Cleanup array and print summary */
|
||||
pr_info("MMU: Supported page sizes\n");
|
||||
for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
|
||||
struct mmu_psize_def *def = &mmu_psize_defs[psize];
|
||||
const char *__page_type_names[] = {
|
||||
"unsupported",
|
||||
"direct",
|
||||
"indirect",
|
||||
"direct & indirect"
|
||||
};
|
||||
if (def->flags == 0) {
|
||||
def->shift = 0;
|
||||
continue;
|
||||
}
|
||||
pr_info(" %8ld KB as %s\n", 1ul << (def->shift - 10),
|
||||
__page_type_names[def->flags & 0x3]);
|
||||
}
|
||||
}
|
||||
|
||||
static void __init setup_mmu_htw(void)
|
||||
{
|
||||
/*
|
||||
* If we want to use HW tablewalk, enable it by patching the TLB miss
|
||||
* handlers to branch to the one dedicated to it.
|
||||
*/
|
||||
|
||||
switch (book3e_htw_mode) {
|
||||
#ifdef CONFIG_PPC_E500
|
||||
case PPC_HTW_E6500:
|
||||
extlb_level_exc = EX_TLB_SIZE;
|
||||
patch_exception(0x1c0, exc_data_tlb_miss_e6500_book3e);
|
||||
patch_exception(0x1e0, exc_instruction_tlb_miss_e6500_book3e);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
pr_info("MMU: Book3E HW tablewalk %s\n",
|
||||
book3e_htw_mode != PPC_HTW_NONE ? "enabled" : "not supported");
|
||||
}
|
||||
|
||||
/*
|
||||
* Early initialization of the MMU TLB code
|
||||
*/
|
||||
static void early_init_this_mmu(void)
|
||||
{
|
||||
unsigned int mas4;
|
||||
|
||||
/* Set MAS4 based on page table setting */
|
||||
|
||||
mas4 = 0x4 << MAS4_WIMGED_SHIFT;
|
||||
switch (book3e_htw_mode) {
|
||||
case PPC_HTW_E6500:
|
||||
mas4 |= MAS4_INDD;
|
||||
mas4 |= BOOK3E_PAGESZ_2M << MAS4_TSIZED_SHIFT;
|
||||
mas4 |= MAS4_TLBSELD(1);
|
||||
mmu_pte_psize = MMU_PAGE_2M;
|
||||
break;
|
||||
|
||||
case PPC_HTW_NONE:
|
||||
mas4 |= BOOK3E_PAGESZ_4K << MAS4_TSIZED_SHIFT;
|
||||
mmu_pte_psize = mmu_virtual_psize;
|
||||
break;
|
||||
}
|
||||
mtspr(SPRN_MAS4, mas4);
|
||||
|
||||
#ifdef CONFIG_PPC_E500
|
||||
if (mmu_has_feature(MMU_FTR_TYPE_FSL_E)) {
|
||||
unsigned int num_cams;
|
||||
bool map = true;
|
||||
|
||||
/* use a quarter of the TLBCAM for bolted linear map */
|
||||
num_cams = (mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY) / 4;
|
||||
|
||||
/*
|
||||
* Only do the mapping once per core, or else the
|
||||
* transient mapping would cause problems.
|
||||
*/
|
||||
#ifdef CONFIG_SMP
|
||||
if (hweight32(get_tensr()) > 1)
|
||||
map = false;
|
||||
#endif
|
||||
|
||||
if (map)
|
||||
linear_map_top = map_mem_in_cams(linear_map_top,
|
||||
num_cams, false, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* A sync won't hurt us after mucking around with
|
||||
* the MMU configuration
|
||||
*/
|
||||
mb();
|
||||
}
|
||||
|
||||
static void __init early_init_mmu_global(void)
|
||||
{
|
||||
/* XXX This should be decided at runtime based on supported
|
||||
* page sizes in the TLB, but for now let's assume 16M is
|
||||
* always there and a good fit (which it probably is)
|
||||
*
|
||||
* Freescale booke only supports 4K pages in TLB0, so use that.
|
||||
*/
|
||||
if (mmu_has_feature(MMU_FTR_TYPE_FSL_E))
|
||||
mmu_vmemmap_psize = MMU_PAGE_4K;
|
||||
else
|
||||
mmu_vmemmap_psize = MMU_PAGE_16M;
|
||||
|
||||
/* XXX This code only checks for TLB 0 capabilities and doesn't
|
||||
* check what page size combos are supported by the HW. It
|
||||
* also doesn't handle the case where a separate array holds
|
||||
* the IND entries from the array loaded by the PT.
|
||||
*/
|
||||
/* Look for supported page sizes */
|
||||
setup_page_sizes();
|
||||
|
||||
/* Look for HW tablewalk support */
|
||||
setup_mmu_htw();
|
||||
|
||||
#ifdef CONFIG_PPC_E500
|
||||
if (mmu_has_feature(MMU_FTR_TYPE_FSL_E)) {
|
||||
if (book3e_htw_mode == PPC_HTW_NONE) {
|
||||
extlb_level_exc = EX_TLB_SIZE;
|
||||
patch_exception(0x1c0, exc_data_tlb_miss_bolted_book3e);
|
||||
patch_exception(0x1e0,
|
||||
exc_instruction_tlb_miss_bolted_book3e);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set the global containing the top of the linear mapping
|
||||
* for use by the TLB miss code
|
||||
*/
|
||||
linear_map_top = memblock_end_of_DRAM();
|
||||
|
||||
ioremap_bot = IOREMAP_BASE;
|
||||
}
|
||||
|
||||
static void __init early_mmu_set_memory_limit(void)
|
||||
{
|
||||
#ifdef CONFIG_PPC_E500
|
||||
if (mmu_has_feature(MMU_FTR_TYPE_FSL_E)) {
|
||||
/*
|
||||
* Limit memory so we dont have linear faults.
|
||||
* Unlike memblock_set_current_limit, which limits
|
||||
* memory available during early boot, this permanently
|
||||
* reduces the memory available to Linux. We need to
|
||||
* do this because highmem is not supported on 64-bit.
|
||||
*/
|
||||
memblock_enforce_memory_limit(linear_map_top);
|
||||
}
|
||||
#endif
|
||||
|
||||
memblock_set_current_limit(linear_map_top);
|
||||
}
|
||||
|
||||
/* boot cpu only */
|
||||
void __init early_init_mmu(void)
|
||||
{
|
||||
early_init_mmu_global();
|
||||
early_init_this_mmu();
|
||||
early_mmu_set_memory_limit();
|
||||
}
|
||||
|
||||
void early_init_mmu_secondary(void)
|
||||
{
|
||||
early_init_this_mmu();
|
||||
}
|
||||
|
||||
void setup_initial_memory_limit(phys_addr_t first_memblock_base,
|
||||
phys_addr_t first_memblock_size)
|
||||
{
|
||||
/* On non-FSL Embedded 64-bit, we adjust the RMA size to match
|
||||
* the bolted TLB entry. We know for now that only 1G
|
||||
* entries are supported though that may eventually
|
||||
* change.
|
||||
*
|
||||
* on FSL Embedded 64-bit, usually all RAM is bolted, but with
|
||||
* unusual memory sizes it's possible for some RAM to not be mapped
|
||||
* (such RAM is not used at all by Linux, since we don't support
|
||||
* highmem on 64-bit). We limit ppc64_rma_size to what would be
|
||||
* mappable if this memblock is the only one. Additional memblocks
|
||||
* can only increase, not decrease, the amount that ends up getting
|
||||
* mapped. We still limit max to 1G even if we'll eventually map
|
||||
* more. This is due to what the early init code is set up to do.
|
||||
*
|
||||
* We crop it to the size of the first MEMBLOCK to
|
||||
* avoid going over total available memory just in case...
|
||||
*/
|
||||
#ifdef CONFIG_PPC_E500
|
||||
if (early_mmu_has_feature(MMU_FTR_TYPE_FSL_E)) {
|
||||
unsigned long linear_sz;
|
||||
unsigned int num_cams;
|
||||
|
||||
/* use a quarter of the TLBCAM for bolted linear map */
|
||||
num_cams = (mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY) / 4;
|
||||
|
||||
linear_sz = map_mem_in_cams(first_memblock_size, num_cams,
|
||||
true, true);
|
||||
|
||||
ppc64_rma_size = min_t(u64, linear_sz, 0x40000000);
|
||||
} else
|
||||
#endif
|
||||
ppc64_rma_size = min_t(u64, first_memblock_size, 0x40000000);
|
||||
|
||||
/* Finally limit subsequent allocations */
|
||||
memblock_set_current_limit(first_memblock_base + ppc64_rma_size);
|
||||
}
|
||||
@@ -893,201 +893,6 @@ virt_page_table_tlb_miss_whacko_fault:
|
||||
TLB_MISS_EPILOG_ERROR
|
||||
b exc_data_storage_book3e
|
||||
|
||||
|
||||
/**************************************************************
|
||||
* *
|
||||
* TLB miss handling for Book3E with hw page table support *
|
||||
* *
|
||||
**************************************************************/
|
||||
|
||||
|
||||
/* Data TLB miss */
|
||||
START_EXCEPTION(data_tlb_miss_htw)
|
||||
TLB_MISS_PROLOG
|
||||
|
||||
/* Now we handle the fault proper. We only save DEAR in normal
|
||||
* fault case since that's the only interesting values here.
|
||||
* We could probably also optimize by not saving SRR0/1 in the
|
||||
* linear mapping case but I'll leave that for later
|
||||
*/
|
||||
mfspr r14,SPRN_ESR
|
||||
mfspr r16,SPRN_DEAR /* get faulting address */
|
||||
srdi r11,r16,44 /* get region */
|
||||
xoris r11,r11,0xc
|
||||
cmpldi cr0,r11,0 /* linear mapping ? */
|
||||
beq tlb_load_linear /* yes -> go to linear map load */
|
||||
cmpldi cr1,r11,1 /* vmalloc mapping ? */
|
||||
|
||||
/* We do the user/kernel test for the PID here along with the RW test
|
||||
*/
|
||||
srdi. r11,r16,60 /* Check for user region */
|
||||
ld r15,PACAPGD(r13) /* Load user pgdir */
|
||||
beq htw_tlb_miss
|
||||
|
||||
/* XXX replace the RMW cycles with immediate loads + writes */
|
||||
1: mfspr r10,SPRN_MAS1
|
||||
rlwinm r10,r10,0,16,1 /* Clear TID */
|
||||
mtspr SPRN_MAS1,r10
|
||||
ld r15,PACA_KERNELPGD(r13) /* Load kernel pgdir */
|
||||
beq+ cr1,htw_tlb_miss
|
||||
|
||||
/* We got a crappy address, just fault with whatever DEAR and ESR
|
||||
* are here
|
||||
*/
|
||||
TLB_MISS_EPILOG_ERROR
|
||||
b exc_data_storage_book3e
|
||||
|
||||
/* Instruction TLB miss */
|
||||
START_EXCEPTION(instruction_tlb_miss_htw)
|
||||
TLB_MISS_PROLOG
|
||||
|
||||
/* If we take a recursive fault, the second level handler may need
|
||||
* to know whether we are handling a data or instruction fault in
|
||||
* order to get to the right store fault handler. We provide that
|
||||
* info by keeping a crazy value for ESR in r14
|
||||
*/
|
||||
li r14,-1 /* store to exception frame is done later */
|
||||
|
||||
/* Now we handle the fault proper. We only save DEAR in the non
|
||||
* linear mapping case since we know the linear mapping case will
|
||||
* not re-enter. We could indeed optimize and also not save SRR0/1
|
||||
* in the linear mapping case but I'll leave that for later
|
||||
*
|
||||
* Faulting address is SRR0 which is already in r16
|
||||
*/
|
||||
srdi r11,r16,44 /* get region */
|
||||
xoris r11,r11,0xc
|
||||
cmpldi cr0,r11,0 /* linear mapping ? */
|
||||
beq tlb_load_linear /* yes -> go to linear map load */
|
||||
cmpldi cr1,r11,1 /* vmalloc mapping ? */
|
||||
|
||||
/* We do the user/kernel test for the PID here along with the RW test
|
||||
*/
|
||||
srdi. r11,r16,60 /* Check for user region */
|
||||
ld r15,PACAPGD(r13) /* Load user pgdir */
|
||||
beq htw_tlb_miss
|
||||
|
||||
/* XXX replace the RMW cycles with immediate loads + writes */
|
||||
1: mfspr r10,SPRN_MAS1
|
||||
rlwinm r10,r10,0,16,1 /* Clear TID */
|
||||
mtspr SPRN_MAS1,r10
|
||||
ld r15,PACA_KERNELPGD(r13) /* Load kernel pgdir */
|
||||
beq+ htw_tlb_miss
|
||||
|
||||
/* We got a crappy address, just fault */
|
||||
TLB_MISS_EPILOG_ERROR
|
||||
b exc_instruction_storage_book3e
|
||||
|
||||
|
||||
/*
|
||||
* This is the guts of the second-level TLB miss handler for direct
|
||||
* misses. We are entered with:
|
||||
*
|
||||
* r16 = virtual page table faulting address
|
||||
* r15 = PGD pointer
|
||||
* r14 = ESR
|
||||
* r13 = PACA
|
||||
* r12 = TLB exception frame in PACA
|
||||
* r11 = crap (free to use)
|
||||
* r10 = crap (free to use)
|
||||
*
|
||||
* It can be re-entered by the linear mapping miss handler. However, to
|
||||
* avoid too much complication, it will save/restore things for us
|
||||
*/
|
||||
htw_tlb_miss:
|
||||
#ifdef CONFIG_PPC_KUAP
|
||||
mfspr r10,SPRN_MAS1
|
||||
rlwinm. r10,r10,0,0x3fff0000
|
||||
beq- htw_tlb_miss_fault /* KUAP fault */
|
||||
#endif
|
||||
/* Search if we already have a TLB entry for that virtual address, and
|
||||
* if we do, bail out.
|
||||
*
|
||||
* MAS1:IND should be already set based on MAS4
|
||||
*/
|
||||
PPC_TLBSRX_DOT(0,R16)
|
||||
beq htw_tlb_miss_done
|
||||
|
||||
/* Now, we need to walk the page tables. First check if we are in
|
||||
* range.
|
||||
*/
|
||||
rldicl. r10,r16,64-PGTABLE_EADDR_SIZE,PGTABLE_EADDR_SIZE+4
|
||||
bne- htw_tlb_miss_fault
|
||||
|
||||
/* Get the PGD pointer */
|
||||
cmpldi cr0,r15,0
|
||||
beq- htw_tlb_miss_fault
|
||||
|
||||
/* Get to PGD entry */
|
||||
rldicl r11,r16,64-(PGDIR_SHIFT-3),64-PGD_INDEX_SIZE-3
|
||||
clrrdi r10,r11,3
|
||||
ldx r15,r10,r15
|
||||
cmpdi cr0,r15,0
|
||||
bge htw_tlb_miss_fault
|
||||
|
||||
/* Get to PUD entry */
|
||||
rldicl r11,r16,64-(PUD_SHIFT-3),64-PUD_INDEX_SIZE-3
|
||||
clrrdi r10,r11,3
|
||||
ldx r15,r10,r15
|
||||
cmpdi cr0,r15,0
|
||||
bge htw_tlb_miss_fault
|
||||
|
||||
/* Get to PMD entry */
|
||||
rldicl r11,r16,64-(PMD_SHIFT-3),64-PMD_INDEX_SIZE-3
|
||||
clrrdi r10,r11,3
|
||||
ldx r15,r10,r15
|
||||
cmpdi cr0,r15,0
|
||||
bge htw_tlb_miss_fault
|
||||
|
||||
/* Ok, we're all right, we can now create an indirect entry for
|
||||
* a 1M or 256M page.
|
||||
*
|
||||
* The last trick is now that because we use "half" pages for
|
||||
* the HTW (1M IND is 2K and 256M IND is 32K) we need to account
|
||||
* for an added LSB bit to the RPN. For 64K pages, there is no
|
||||
* problem as we already use 32K arrays (half PTE pages), but for
|
||||
* 4K page we need to extract a bit from the virtual address and
|
||||
* insert it into the "PA52" bit of the RPN.
|
||||
*/
|
||||
rlwimi r15,r16,32-9,20,20
|
||||
/* Now we build the MAS:
|
||||
*
|
||||
* MAS 0 : Fully setup with defaults in MAS4 and TLBnCFG
|
||||
* MAS 1 : Almost fully setup
|
||||
* - PID already updated by caller if necessary
|
||||
* - TSIZE for now is base ind page size always
|
||||
* MAS 2 : Use defaults
|
||||
* MAS 3+7 : Needs to be done
|
||||
*/
|
||||
ori r10,r15,(BOOK3E_PAGESZ_4K << MAS3_SPSIZE_SHIFT)
|
||||
|
||||
srdi r16,r10,32
|
||||
mtspr SPRN_MAS3,r10
|
||||
mtspr SPRN_MAS7,r16
|
||||
|
||||
tlbwe
|
||||
|
||||
htw_tlb_miss_done:
|
||||
/* We don't bother with restoring DEAR or ESR since we know we are
|
||||
* level 0 and just going back to userland. They are only needed
|
||||
* if you are going to take an access fault
|
||||
*/
|
||||
TLB_MISS_EPILOG_SUCCESS
|
||||
rfi
|
||||
|
||||
htw_tlb_miss_fault:
|
||||
/* We need to check if it was an instruction miss. We know this
|
||||
* though because r14 would contain -1
|
||||
*/
|
||||
cmpdi cr0,r14,-1
|
||||
beq 1f
|
||||
mtspr SPRN_DEAR,r16
|
||||
mtspr SPRN_ESR,r14
|
||||
TLB_MISS_EPILOG_ERROR
|
||||
b exc_data_storage_book3e
|
||||
1: TLB_MISS_EPILOG_ERROR
|
||||
b exc_instruction_storage_book3e
|
||||
|
||||
/*
|
||||
* This is the guts of "any" level TLB miss handler for kernel linear
|
||||
* mapping misses. We are entered with:
|
||||
|
||||
@@ -241,7 +241,7 @@ static pmd_t *pti_user_pagetable_walk_pmd(unsigned long address)
|
||||
*
|
||||
* Returns a pointer to a PTE on success, or NULL on failure.
|
||||
*/
|
||||
static pte_t *pti_user_pagetable_walk_pte(unsigned long address)
|
||||
static pte_t *pti_user_pagetable_walk_pte(unsigned long address, bool late_text)
|
||||
{
|
||||
gfp_t gfp = (GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO);
|
||||
pmd_t *pmd;
|
||||
@@ -251,10 +251,15 @@ static pte_t *pti_user_pagetable_walk_pte(unsigned long address)
|
||||
if (!pmd)
|
||||
return NULL;
|
||||
|
||||
/* We can't do anything sensible if we hit a large mapping. */
|
||||
/* Large PMD mapping found */
|
||||
if (pmd_large(*pmd)) {
|
||||
WARN_ON(1);
|
||||
return NULL;
|
||||
/* Clear the PMD if we hit a large mapping from the first round */
|
||||
if (late_text) {
|
||||
set_pmd(pmd, __pmd(0));
|
||||
} else {
|
||||
WARN_ON_ONCE(1);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (pmd_none(*pmd)) {
|
||||
@@ -283,7 +288,7 @@ static void __init pti_setup_vsyscall(void)
|
||||
if (!pte || WARN_ON(level != PG_LEVEL_4K) || pte_none(*pte))
|
||||
return;
|
||||
|
||||
target_pte = pti_user_pagetable_walk_pte(VSYSCALL_ADDR);
|
||||
target_pte = pti_user_pagetable_walk_pte(VSYSCALL_ADDR, false);
|
||||
if (WARN_ON(!target_pte))
|
||||
return;
|
||||
|
||||
@@ -301,7 +306,7 @@ enum pti_clone_level {
|
||||
|
||||
static void
|
||||
pti_clone_pgtable(unsigned long start, unsigned long end,
|
||||
enum pti_clone_level level)
|
||||
enum pti_clone_level level, bool late_text)
|
||||
{
|
||||
unsigned long addr;
|
||||
|
||||
@@ -390,7 +395,7 @@ pti_clone_pgtable(unsigned long start, unsigned long end,
|
||||
return;
|
||||
|
||||
/* Allocate PTE in the user page-table */
|
||||
target_pte = pti_user_pagetable_walk_pte(addr);
|
||||
target_pte = pti_user_pagetable_walk_pte(addr, late_text);
|
||||
if (WARN_ON(!target_pte))
|
||||
return;
|
||||
|
||||
@@ -452,7 +457,7 @@ static void __init pti_clone_user_shared(void)
|
||||
phys_addr_t pa = per_cpu_ptr_to_phys((void *)va);
|
||||
pte_t *target_pte;
|
||||
|
||||
target_pte = pti_user_pagetable_walk_pte(va);
|
||||
target_pte = pti_user_pagetable_walk_pte(va, false);
|
||||
if (WARN_ON(!target_pte))
|
||||
return;
|
||||
|
||||
@@ -475,7 +480,7 @@ static void __init pti_clone_user_shared(void)
|
||||
start = CPU_ENTRY_AREA_BASE;
|
||||
end = start + (PAGE_SIZE * CPU_ENTRY_AREA_PAGES);
|
||||
|
||||
pti_clone_pgtable(start, end, PTI_CLONE_PMD);
|
||||
pti_clone_pgtable(start, end, PTI_CLONE_PMD, false);
|
||||
}
|
||||
#endif /* CONFIG_X86_64 */
|
||||
|
||||
@@ -492,11 +497,11 @@ static void __init pti_setup_espfix64(void)
|
||||
/*
|
||||
* Clone the populated PMDs of the entry text and force it RO.
|
||||
*/
|
||||
static void pti_clone_entry_text(void)
|
||||
static void pti_clone_entry_text(bool late)
|
||||
{
|
||||
pti_clone_pgtable((unsigned long) __entry_text_start,
|
||||
(unsigned long) __entry_text_end,
|
||||
PTI_LEVEL_KERNEL_IMAGE);
|
||||
PTI_LEVEL_KERNEL_IMAGE, late);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -571,7 +576,7 @@ static void pti_clone_kernel_text(void)
|
||||
* pti_set_kernel_image_nonglobal() did to clear the
|
||||
* global bit.
|
||||
*/
|
||||
pti_clone_pgtable(start, end_clone, PTI_LEVEL_KERNEL_IMAGE);
|
||||
pti_clone_pgtable(start, end_clone, PTI_LEVEL_KERNEL_IMAGE, false);
|
||||
|
||||
/*
|
||||
* pti_clone_pgtable() will set the global bit in any PMDs
|
||||
@@ -638,8 +643,15 @@ void __init pti_init(void)
|
||||
|
||||
/* Undo all global bits from the init pagetables in head_64.S: */
|
||||
pti_set_kernel_image_nonglobal();
|
||||
|
||||
/* Replace some of the global bits just for shared entry text: */
|
||||
pti_clone_entry_text();
|
||||
/*
|
||||
* This is very early in boot. Device and Late initcalls can do
|
||||
* modprobe before free_initmem() and mark_readonly(). This
|
||||
* pti_clone_entry_text() allows those user-mode-helpers to function,
|
||||
* but notably the text is still RW.
|
||||
*/
|
||||
pti_clone_entry_text(false);
|
||||
pti_setup_espfix64();
|
||||
pti_setup_vsyscall();
|
||||
}
|
||||
@@ -656,10 +668,11 @@ void pti_finalize(void)
|
||||
if (!boot_cpu_has(X86_FEATURE_PTI))
|
||||
return;
|
||||
/*
|
||||
* We need to clone everything (again) that maps parts of the
|
||||
* kernel image.
|
||||
* This is after free_initmem() (all initcalls are done) and we've done
|
||||
* mark_readonly(). Text is now NX which might've split some PMDs
|
||||
* relative to the early clone.
|
||||
*/
|
||||
pti_clone_entry_text();
|
||||
pti_clone_entry_text(true);
|
||||
pti_clone_kernel_text();
|
||||
|
||||
debug_checkwx_user();
|
||||
|
||||
@@ -373,7 +373,7 @@ static int acpi_processor_add(struct acpi_device *device,
|
||||
|
||||
result = acpi_processor_get_info(device);
|
||||
if (result) /* Processor is not physically present or unavailable */
|
||||
return 0;
|
||||
goto err_clear_driver_data;
|
||||
|
||||
BUG_ON(pr->id >= nr_cpu_ids);
|
||||
|
||||
@@ -388,7 +388,7 @@ static int acpi_processor_add(struct acpi_device *device,
|
||||
"BIOS reported wrong ACPI id %d for the processor\n",
|
||||
pr->id);
|
||||
/* Give up, but do not abort the namespace scan. */
|
||||
goto err;
|
||||
goto err_clear_driver_data;
|
||||
}
|
||||
/*
|
||||
* processor_device_array is not cleared on errors to allow buggy BIOS
|
||||
@@ -400,12 +400,12 @@ static int acpi_processor_add(struct acpi_device *device,
|
||||
dev = get_cpu_device(pr->id);
|
||||
if (!dev) {
|
||||
result = -ENODEV;
|
||||
goto err;
|
||||
goto err_clear_per_cpu;
|
||||
}
|
||||
|
||||
result = acpi_bind_one(dev, device);
|
||||
if (result)
|
||||
goto err;
|
||||
goto err_clear_per_cpu;
|
||||
|
||||
pr->dev = dev;
|
||||
|
||||
@@ -416,10 +416,11 @@ static int acpi_processor_add(struct acpi_device *device,
|
||||
dev_err(dev, "Processor driver could not be attached\n");
|
||||
acpi_unbind_one(dev);
|
||||
|
||||
err:
|
||||
free_cpumask_var(pr->throttling.shared_cpu_map);
|
||||
device->driver_data = NULL;
|
||||
err_clear_per_cpu:
|
||||
per_cpu(processors, pr->id) = NULL;
|
||||
err_clear_driver_data:
|
||||
device->driver_data = NULL;
|
||||
free_cpumask_var(pr->throttling.shared_cpu_map);
|
||||
err_free_pr:
|
||||
kfree(pr);
|
||||
return result;
|
||||
|
||||
@@ -1915,6 +1915,8 @@ static int ublk_ctrl_start_recovery(struct ublk_device *ub,
|
||||
mutex_lock(&ub->mutex);
|
||||
if (!ublk_can_use_recovery(ub))
|
||||
goto out_unlock;
|
||||
if (!ub->nr_queues_ready)
|
||||
goto out_unlock;
|
||||
/*
|
||||
* START_RECOVERY is only allowd after:
|
||||
*
|
||||
|
||||
@@ -713,6 +713,7 @@ static int rockchip_gpio_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
|
||||
pctldev = of_pinctrl_get(pctlnp);
|
||||
of_node_put(pctlnp);
|
||||
if (!pctldev)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
|
||||
@@ -146,6 +146,7 @@ static const struct of_device_id modepin_platform_id[] = {
|
||||
{ .compatible = "xlnx,zynqmp-gpio-modepin", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, modepin_platform_id);
|
||||
|
||||
static struct platform_driver modepin_platform_driver = {
|
||||
.driver = {
|
||||
|
||||
@@ -997,6 +997,30 @@ static int amdgpu_display_verify_sizes(struct amdgpu_framebuffer *rfb)
|
||||
block_width = 256 / format_info->cpp[i];
|
||||
block_height = 1;
|
||||
block_size_log2 = 8;
|
||||
} else if (AMD_FMT_MOD_GET(TILE_VERSION, modifier) >= AMD_FMT_MOD_TILE_VER_GFX12) {
|
||||
int swizzle = AMD_FMT_MOD_GET(TILE, modifier);
|
||||
|
||||
switch (swizzle) {
|
||||
case AMD_FMT_MOD_TILE_GFX12_256B_2D:
|
||||
block_size_log2 = 8;
|
||||
break;
|
||||
case AMD_FMT_MOD_TILE_GFX12_4K_2D:
|
||||
block_size_log2 = 12;
|
||||
break;
|
||||
case AMD_FMT_MOD_TILE_GFX12_64K_2D:
|
||||
block_size_log2 = 16;
|
||||
break;
|
||||
case AMD_FMT_MOD_TILE_GFX12_256K_2D:
|
||||
block_size_log2 = 18;
|
||||
break;
|
||||
default:
|
||||
drm_dbg_kms(rfb->base.dev,
|
||||
"Gfx12 swizzle mode with unknown block size: %d\n", swizzle);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
get_block_dimensions(block_size_log2, format_info->cpp[i],
|
||||
&block_width, &block_height);
|
||||
} else {
|
||||
int swizzle = AMD_FMT_MOD_GET(TILE, modifier);
|
||||
|
||||
@@ -1032,7 +1056,8 @@ static int amdgpu_display_verify_sizes(struct amdgpu_framebuffer *rfb)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (AMD_FMT_MOD_GET(DCC, modifier)) {
|
||||
if (AMD_FMT_MOD_GET(TILE_VERSION, modifier) <= AMD_FMT_MOD_TILE_VER_GFX11 &&
|
||||
AMD_FMT_MOD_GET(DCC, modifier)) {
|
||||
if (AMD_FMT_MOD_GET(DCC_RETILE, modifier)) {
|
||||
block_size_log2 = get_dcc_block_size(modifier, false, false);
|
||||
get_block_dimensions(block_size_log2 + 8, format_info->cpp[0],
|
||||
|
||||
@@ -51,7 +51,7 @@ static inline void debug_fence_init(struct i915_sw_fence *fence)
|
||||
debug_object_init(fence, &i915_sw_fence_debug_descr);
|
||||
}
|
||||
|
||||
static inline void debug_fence_init_onstack(struct i915_sw_fence *fence)
|
||||
static inline __maybe_unused void debug_fence_init_onstack(struct i915_sw_fence *fence)
|
||||
{
|
||||
debug_object_init_on_stack(fence, &i915_sw_fence_debug_descr);
|
||||
}
|
||||
@@ -77,7 +77,7 @@ static inline void debug_fence_destroy(struct i915_sw_fence *fence)
|
||||
debug_object_destroy(fence, &i915_sw_fence_debug_descr);
|
||||
}
|
||||
|
||||
static inline void debug_fence_free(struct i915_sw_fence *fence)
|
||||
static inline __maybe_unused void debug_fence_free(struct i915_sw_fence *fence)
|
||||
{
|
||||
debug_object_free(fence, &i915_sw_fence_debug_descr);
|
||||
smp_wmb(); /* flush the change in state before reallocation */
|
||||
@@ -94,7 +94,7 @@ static inline void debug_fence_init(struct i915_sw_fence *fence)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void debug_fence_init_onstack(struct i915_sw_fence *fence)
|
||||
static inline __maybe_unused void debug_fence_init_onstack(struct i915_sw_fence *fence)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ static inline void debug_fence_destroy(struct i915_sw_fence *fence)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void debug_fence_free(struct i915_sw_fence *fence)
|
||||
static inline __maybe_unused void debug_fence_free(struct i915_sw_fence *fence)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
|
||||
//
|
||||
// Copyright (c) 2019, 2020, 2021 Pengutronix,
|
||||
// Copyright (c) 2019, 2020, 2021, 2023 Pengutronix,
|
||||
// Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
//
|
||||
// Based on:
|
||||
@@ -867,18 +867,18 @@ static int mcp251xfd_get_berr_counter(const struct net_device *ndev,
|
||||
|
||||
static struct sk_buff *
|
||||
mcp251xfd_alloc_can_err_skb(struct mcp251xfd_priv *priv,
|
||||
struct can_frame **cf, u32 *timestamp)
|
||||
struct can_frame **cf, u32 *ts_raw)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int err;
|
||||
|
||||
err = mcp251xfd_get_timestamp(priv, timestamp);
|
||||
err = mcp251xfd_get_timestamp_raw(priv, ts_raw);
|
||||
if (err)
|
||||
return NULL;
|
||||
|
||||
skb = alloc_can_err_skb(priv->ndev, cf);
|
||||
if (skb)
|
||||
mcp251xfd_skb_set_timestamp(priv, skb, *timestamp);
|
||||
mcp251xfd_skb_set_timestamp_raw(priv, skb, *ts_raw);
|
||||
|
||||
return skb;
|
||||
}
|
||||
@@ -889,7 +889,7 @@ static int mcp251xfd_handle_rxovif(struct mcp251xfd_priv *priv)
|
||||
struct mcp251xfd_rx_ring *ring;
|
||||
struct sk_buff *skb;
|
||||
struct can_frame *cf;
|
||||
u32 timestamp, rxovif;
|
||||
u32 ts_raw, rxovif;
|
||||
int err, i;
|
||||
|
||||
stats->rx_over_errors++;
|
||||
@@ -924,14 +924,14 @@ static int mcp251xfd_handle_rxovif(struct mcp251xfd_priv *priv)
|
||||
return err;
|
||||
}
|
||||
|
||||
skb = mcp251xfd_alloc_can_err_skb(priv, &cf, ×tamp);
|
||||
skb = mcp251xfd_alloc_can_err_skb(priv, &cf, &ts_raw);
|
||||
if (!skb)
|
||||
return 0;
|
||||
|
||||
cf->can_id |= CAN_ERR_CRTL;
|
||||
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
|
||||
|
||||
err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp);
|
||||
err = can_rx_offload_queue_timestamp(&priv->offload, skb, ts_raw);
|
||||
if (err)
|
||||
stats->rx_fifo_errors++;
|
||||
|
||||
@@ -948,12 +948,12 @@ static int mcp251xfd_handle_txatif(struct mcp251xfd_priv *priv)
|
||||
static int mcp251xfd_handle_ivmif(struct mcp251xfd_priv *priv)
|
||||
{
|
||||
struct net_device_stats *stats = &priv->ndev->stats;
|
||||
u32 bdiag1, timestamp;
|
||||
u32 bdiag1, ts_raw;
|
||||
struct sk_buff *skb;
|
||||
struct can_frame *cf = NULL;
|
||||
int err;
|
||||
|
||||
err = mcp251xfd_get_timestamp(priv, ×tamp);
|
||||
err = mcp251xfd_get_timestamp_raw(priv, &ts_raw);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -1035,8 +1035,8 @@ static int mcp251xfd_handle_ivmif(struct mcp251xfd_priv *priv)
|
||||
if (!cf)
|
||||
return 0;
|
||||
|
||||
mcp251xfd_skb_set_timestamp(priv, skb, timestamp);
|
||||
err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp);
|
||||
mcp251xfd_skb_set_timestamp_raw(priv, skb, ts_raw);
|
||||
err = can_rx_offload_queue_timestamp(&priv->offload, skb, ts_raw);
|
||||
if (err)
|
||||
stats->rx_fifo_errors++;
|
||||
|
||||
@@ -1049,7 +1049,7 @@ static int mcp251xfd_handle_cerrif(struct mcp251xfd_priv *priv)
|
||||
struct sk_buff *skb;
|
||||
struct can_frame *cf = NULL;
|
||||
enum can_state new_state, rx_state, tx_state;
|
||||
u32 trec, timestamp;
|
||||
u32 trec, ts_raw;
|
||||
int err;
|
||||
|
||||
err = regmap_read(priv->map_reg, MCP251XFD_REG_TREC, &trec);
|
||||
@@ -1079,7 +1079,7 @@ static int mcp251xfd_handle_cerrif(struct mcp251xfd_priv *priv)
|
||||
/* The skb allocation might fail, but can_change_state()
|
||||
* handles cf == NULL.
|
||||
*/
|
||||
skb = mcp251xfd_alloc_can_err_skb(priv, &cf, ×tamp);
|
||||
skb = mcp251xfd_alloc_can_err_skb(priv, &cf, &ts_raw);
|
||||
can_change_state(priv->ndev, cf, tx_state, rx_state);
|
||||
|
||||
if (new_state == CAN_STATE_BUS_OFF) {
|
||||
@@ -1110,7 +1110,7 @@ static int mcp251xfd_handle_cerrif(struct mcp251xfd_priv *priv)
|
||||
cf->data[7] = bec.rxerr;
|
||||
}
|
||||
|
||||
err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp);
|
||||
err = can_rx_offload_queue_timestamp(&priv->offload, skb, ts_raw);
|
||||
if (err)
|
||||
stats->rx_fifo_errors++;
|
||||
|
||||
|
||||
@@ -196,6 +196,7 @@ mcp251xfd_ring_init_rx(struct mcp251xfd_priv *priv, u16 *base, u8 *fifo_nr)
|
||||
int i, j;
|
||||
|
||||
mcp251xfd_for_each_rx_ring(priv, rx_ring, i) {
|
||||
rx_ring->last_valid = timecounter_read(&priv->tc);
|
||||
rx_ring->head = 0;
|
||||
rx_ring->tail = 0;
|
||||
rx_ring->base = *base;
|
||||
@@ -513,6 +514,8 @@ int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv)
|
||||
}
|
||||
|
||||
rx_ring->obj_num = rx_obj_num;
|
||||
rx_ring->obj_num_shift_to_u8 = BITS_PER_TYPE(rx_ring->obj_num_shift_to_u8) -
|
||||
ilog2(rx_obj_num);
|
||||
rx_ring->obj_size = rx_obj_size;
|
||||
priv->rx[i] = rx_ring;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
|
||||
//
|
||||
// Copyright (c) 2019, 2020, 2021 Pengutronix,
|
||||
// Copyright (c) 2019, 2020, 2021, 2023 Pengutronix,
|
||||
// Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
//
|
||||
// Based on:
|
||||
@@ -16,23 +16,14 @@
|
||||
|
||||
#include "mcp251xfd.h"
|
||||
|
||||
static inline int
|
||||
mcp251xfd_rx_head_get_from_chip(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_rx_ring *ring,
|
||||
u8 *rx_head, bool *fifo_empty)
|
||||
static inline bool mcp251xfd_rx_fifo_sta_empty(const u32 fifo_sta)
|
||||
{
|
||||
u32 fifo_sta;
|
||||
int err;
|
||||
return !(fifo_sta & MCP251XFD_REG_FIFOSTA_TFNRFNIF);
|
||||
}
|
||||
|
||||
err = regmap_read(priv->map_reg, MCP251XFD_REG_FIFOSTA(ring->fifo_nr),
|
||||
&fifo_sta);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
*rx_head = FIELD_GET(MCP251XFD_REG_FIFOSTA_FIFOCI_MASK, fifo_sta);
|
||||
*fifo_empty = !(fifo_sta & MCP251XFD_REG_FIFOSTA_TFNRFNIF);
|
||||
|
||||
return 0;
|
||||
static inline bool mcp251xfd_rx_fifo_sta_full(const u32 fifo_sta)
|
||||
{
|
||||
return fifo_sta & MCP251XFD_REG_FIFOSTA_TFERFFIF;
|
||||
}
|
||||
|
||||
static inline int
|
||||
@@ -80,29 +71,49 @@ mcp251xfd_check_rx_tail(const struct mcp251xfd_priv *priv,
|
||||
}
|
||||
|
||||
static int
|
||||
mcp251xfd_rx_ring_update(const struct mcp251xfd_priv *priv,
|
||||
struct mcp251xfd_rx_ring *ring)
|
||||
mcp251xfd_get_rx_len(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_rx_ring *ring,
|
||||
u8 *len_p)
|
||||
{
|
||||
u32 new_head;
|
||||
u8 chip_rx_head;
|
||||
bool fifo_empty;
|
||||
const u8 shift = ring->obj_num_shift_to_u8;
|
||||
u8 chip_head, tail, len;
|
||||
u32 fifo_sta;
|
||||
int err;
|
||||
|
||||
err = mcp251xfd_rx_head_get_from_chip(priv, ring, &chip_rx_head,
|
||||
&fifo_empty);
|
||||
if (err || fifo_empty)
|
||||
err = regmap_read(priv->map_reg, MCP251XFD_REG_FIFOSTA(ring->fifo_nr),
|
||||
&fifo_sta);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* chip_rx_head, is the next RX-Object filled by the HW.
|
||||
* The new RX head must be >= the old head.
|
||||
if (mcp251xfd_rx_fifo_sta_empty(fifo_sta)) {
|
||||
*len_p = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mcp251xfd_rx_fifo_sta_full(fifo_sta)) {
|
||||
*len_p = ring->obj_num;
|
||||
return 0;
|
||||
}
|
||||
|
||||
chip_head = FIELD_GET(MCP251XFD_REG_FIFOSTA_FIFOCI_MASK, fifo_sta);
|
||||
|
||||
err = mcp251xfd_check_rx_tail(priv, ring);
|
||||
if (err)
|
||||
return err;
|
||||
tail = mcp251xfd_get_rx_tail(ring);
|
||||
|
||||
/* First shift to full u8. The subtraction works on signed
|
||||
* values, that keeps the difference steady around the u8
|
||||
* overflow. The right shift acts on len, which is an u8.
|
||||
*/
|
||||
new_head = round_down(ring->head, ring->obj_num) + chip_rx_head;
|
||||
if (new_head <= ring->head)
|
||||
new_head += ring->obj_num;
|
||||
BUILD_BUG_ON(sizeof(ring->obj_num) != sizeof(chip_head));
|
||||
BUILD_BUG_ON(sizeof(ring->obj_num) != sizeof(tail));
|
||||
BUILD_BUG_ON(sizeof(ring->obj_num) != sizeof(len));
|
||||
|
||||
ring->head = new_head;
|
||||
len = (chip_head << shift) - (tail << shift);
|
||||
*len_p = len >> shift;
|
||||
|
||||
return mcp251xfd_check_rx_tail(priv, ring);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -148,8 +159,6 @@ mcp251xfd_hw_rx_obj_to_skb(const struct mcp251xfd_priv *priv,
|
||||
|
||||
if (!(hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_RTR))
|
||||
memcpy(cfd->data, hw_rx_obj->data, cfd->len);
|
||||
|
||||
mcp251xfd_skb_set_timestamp(priv, skb, hw_rx_obj->ts);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -160,8 +169,26 @@ mcp251xfd_handle_rxif_one(struct mcp251xfd_priv *priv,
|
||||
struct net_device_stats *stats = &priv->ndev->stats;
|
||||
struct sk_buff *skb;
|
||||
struct canfd_frame *cfd;
|
||||
u64 timestamp;
|
||||
int err;
|
||||
|
||||
/* According to mcp2518fd erratum DS80000789E 6. the FIFOCI
|
||||
* bits of a FIFOSTA register, here the RX FIFO head index
|
||||
* might be corrupted and we might process past the RX FIFO's
|
||||
* head into old CAN frames.
|
||||
*
|
||||
* Compare the timestamp of currently processed CAN frame with
|
||||
* last valid frame received. Abort with -EBADMSG if an old
|
||||
* CAN frame is detected.
|
||||
*/
|
||||
timestamp = timecounter_cyc2time(&priv->tc, hw_rx_obj->ts);
|
||||
if (timestamp <= ring->last_valid) {
|
||||
stats->rx_fifo_errors++;
|
||||
|
||||
return -EBADMSG;
|
||||
}
|
||||
ring->last_valid = timestamp;
|
||||
|
||||
if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_FDF)
|
||||
skb = alloc_canfd_skb(priv->ndev, &cfd);
|
||||
else
|
||||
@@ -172,6 +199,7 @@ mcp251xfd_handle_rxif_one(struct mcp251xfd_priv *priv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
mcp251xfd_skb_set_timestamp(skb, timestamp);
|
||||
mcp251xfd_hw_rx_obj_to_skb(priv, hw_rx_obj, skb);
|
||||
err = can_rx_offload_queue_timestamp(&priv->offload, skb, hw_rx_obj->ts);
|
||||
if (err)
|
||||
@@ -197,52 +225,81 @@ mcp251xfd_rx_obj_read(const struct mcp251xfd_priv *priv,
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
mcp251xfd_handle_rxif_ring_uinc(const struct mcp251xfd_priv *priv,
|
||||
struct mcp251xfd_rx_ring *ring,
|
||||
u8 len)
|
||||
{
|
||||
int offset;
|
||||
int err;
|
||||
|
||||
if (!len)
|
||||
return 0;
|
||||
|
||||
ring->head += len;
|
||||
|
||||
/* Increment the RX FIFO tail pointer 'len' times in a
|
||||
* single SPI message.
|
||||
*
|
||||
* Note:
|
||||
* Calculate offset, so that the SPI transfer ends on
|
||||
* the last message of the uinc_xfer array, which has
|
||||
* "cs_change == 0", to properly deactivate the chip
|
||||
* select.
|
||||
*/
|
||||
offset = ARRAY_SIZE(ring->uinc_xfer) - len;
|
||||
err = spi_sync_transfer(priv->spi,
|
||||
ring->uinc_xfer + offset, len);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ring->tail += len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mcp251xfd_handle_rxif_ring(struct mcp251xfd_priv *priv,
|
||||
struct mcp251xfd_rx_ring *ring)
|
||||
{
|
||||
struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj = ring->obj;
|
||||
u8 rx_tail, len;
|
||||
u8 rx_tail, len, l;
|
||||
int err, i;
|
||||
|
||||
err = mcp251xfd_rx_ring_update(priv, ring);
|
||||
err = mcp251xfd_get_rx_len(priv, ring, &len);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
while ((len = mcp251xfd_get_rx_linear_len(ring))) {
|
||||
int offset;
|
||||
|
||||
while ((l = mcp251xfd_get_rx_linear_len(ring, len))) {
|
||||
rx_tail = mcp251xfd_get_rx_tail(ring);
|
||||
|
||||
err = mcp251xfd_rx_obj_read(priv, ring, hw_rx_obj,
|
||||
rx_tail, len);
|
||||
rx_tail, l);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
for (i = 0; i < l; i++) {
|
||||
err = mcp251xfd_handle_rxif_one(priv, ring,
|
||||
(void *)hw_rx_obj +
|
||||
i * ring->obj_size);
|
||||
if (err)
|
||||
|
||||
/* -EBADMSG means we're affected by mcp2518fd
|
||||
* erratum DS80000789E 6., i.e. the timestamp
|
||||
* in the RX object is older that the last
|
||||
* valid received CAN frame. Don't process any
|
||||
* further and mark processed frames as good.
|
||||
*/
|
||||
if (err == -EBADMSG)
|
||||
return mcp251xfd_handle_rxif_ring_uinc(priv, ring, i);
|
||||
else if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Increment the RX FIFO tail pointer 'len' times in a
|
||||
* single SPI message.
|
||||
*
|
||||
* Note:
|
||||
* Calculate offset, so that the SPI transfer ends on
|
||||
* the last message of the uinc_xfer array, which has
|
||||
* "cs_change == 0", to properly deactivate the chip
|
||||
* select.
|
||||
*/
|
||||
offset = ARRAY_SIZE(ring->uinc_xfer) - len;
|
||||
err = spi_sync_transfer(priv->spi,
|
||||
ring->uinc_xfer + offset, len);
|
||||
err = mcp251xfd_handle_rxif_ring_uinc(priv, ring, l);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ring->tail += len;
|
||||
len -= l;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -97,7 +97,7 @@ mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv,
|
||||
tef_tail = mcp251xfd_get_tef_tail(priv);
|
||||
skb = priv->can.echo_skb[tef_tail];
|
||||
if (skb)
|
||||
mcp251xfd_skb_set_timestamp(priv, skb, hw_tef_obj->ts);
|
||||
mcp251xfd_skb_set_timestamp_raw(priv, skb, hw_tef_obj->ts);
|
||||
stats->tx_bytes +=
|
||||
can_rx_offload_get_echo_skb(&priv->offload,
|
||||
tef_tail, hw_tef_obj->ts,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
|
||||
//
|
||||
// Copyright (c) 2021 Pengutronix,
|
||||
// Copyright (c) 2021, 2023 Pengutronix,
|
||||
// Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
//
|
||||
|
||||
@@ -11,20 +11,20 @@
|
||||
|
||||
#include "mcp251xfd.h"
|
||||
|
||||
static u64 mcp251xfd_timestamp_read(const struct cyclecounter *cc)
|
||||
static u64 mcp251xfd_timestamp_raw_read(const struct cyclecounter *cc)
|
||||
{
|
||||
const struct mcp251xfd_priv *priv;
|
||||
u32 timestamp = 0;
|
||||
u32 ts_raw = 0;
|
||||
int err;
|
||||
|
||||
priv = container_of(cc, struct mcp251xfd_priv, cc);
|
||||
err = mcp251xfd_get_timestamp(priv, ×tamp);
|
||||
err = mcp251xfd_get_timestamp_raw(priv, &ts_raw);
|
||||
if (err)
|
||||
netdev_err(priv->ndev,
|
||||
"Error %d while reading timestamp. HW timestamps may be inaccurate.",
|
||||
err);
|
||||
|
||||
return timestamp;
|
||||
return ts_raw;
|
||||
}
|
||||
|
||||
static void mcp251xfd_timestamp_work(struct work_struct *work)
|
||||
@@ -39,21 +39,11 @@ static void mcp251xfd_timestamp_work(struct work_struct *work)
|
||||
MCP251XFD_TIMESTAMP_WORK_DELAY_SEC * HZ);
|
||||
}
|
||||
|
||||
void mcp251xfd_skb_set_timestamp(const struct mcp251xfd_priv *priv,
|
||||
struct sk_buff *skb, u32 timestamp)
|
||||
{
|
||||
struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb);
|
||||
u64 ns;
|
||||
|
||||
ns = timecounter_cyc2time(&priv->tc, timestamp);
|
||||
hwtstamps->hwtstamp = ns_to_ktime(ns);
|
||||
}
|
||||
|
||||
void mcp251xfd_timestamp_init(struct mcp251xfd_priv *priv)
|
||||
{
|
||||
struct cyclecounter *cc = &priv->cc;
|
||||
|
||||
cc->read = mcp251xfd_timestamp_read;
|
||||
cc->read = mcp251xfd_timestamp_raw_read;
|
||||
cc->mask = CYCLECOUNTER_MASK(32);
|
||||
cc->shift = 1;
|
||||
cc->mult = clocksource_hz2mult(priv->can.clock.freq, cc->shift);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* mcp251xfd - Microchip MCP251xFD Family CAN controller driver
|
||||
*
|
||||
* Copyright (c) 2019, 2020, 2021 Pengutronix,
|
||||
* Copyright (c) 2019, 2020, 2021, 2023 Pengutronix,
|
||||
* Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
* Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org>
|
||||
*/
|
||||
@@ -549,10 +549,14 @@ struct mcp251xfd_rx_ring {
|
||||
unsigned int head;
|
||||
unsigned int tail;
|
||||
|
||||
/* timestamp of the last valid received CAN frame */
|
||||
u64 last_valid;
|
||||
|
||||
u16 base;
|
||||
u8 nr;
|
||||
u8 fifo_nr;
|
||||
u8 obj_num;
|
||||
u8 obj_num_shift_to_u8;
|
||||
u8 obj_size;
|
||||
|
||||
union mcp251xfd_write_reg_buf irq_enable_buf;
|
||||
@@ -793,10 +797,27 @@ mcp251xfd_spi_cmd_write(const struct mcp251xfd_priv *priv,
|
||||
return data;
|
||||
}
|
||||
|
||||
static inline int mcp251xfd_get_timestamp(const struct mcp251xfd_priv *priv,
|
||||
u32 *timestamp)
|
||||
static inline int mcp251xfd_get_timestamp_raw(const struct mcp251xfd_priv *priv,
|
||||
u32 *ts_raw)
|
||||
{
|
||||
return regmap_read(priv->map_reg, MCP251XFD_REG_TBC, timestamp);
|
||||
return regmap_read(priv->map_reg, MCP251XFD_REG_TBC, ts_raw);
|
||||
}
|
||||
|
||||
static inline void mcp251xfd_skb_set_timestamp(struct sk_buff *skb, u64 ns)
|
||||
{
|
||||
struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb);
|
||||
|
||||
hwtstamps->hwtstamp = ns_to_ktime(ns);
|
||||
}
|
||||
|
||||
static inline
|
||||
void mcp251xfd_skb_set_timestamp_raw(const struct mcp251xfd_priv *priv,
|
||||
struct sk_buff *skb, u32 ts_raw)
|
||||
{
|
||||
u64 ns;
|
||||
|
||||
ns = timecounter_cyc2time(&priv->tc, ts_raw);
|
||||
mcp251xfd_skb_set_timestamp(skb, ns);
|
||||
}
|
||||
|
||||
static inline u16 mcp251xfd_get_tef_obj_addr(u8 n)
|
||||
@@ -889,18 +910,9 @@ static inline u8 mcp251xfd_get_rx_tail(const struct mcp251xfd_rx_ring *ring)
|
||||
return ring->tail & (ring->obj_num - 1);
|
||||
}
|
||||
|
||||
static inline u8 mcp251xfd_get_rx_len(const struct mcp251xfd_rx_ring *ring)
|
||||
{
|
||||
return ring->head - ring->tail;
|
||||
}
|
||||
|
||||
static inline u8
|
||||
mcp251xfd_get_rx_linear_len(const struct mcp251xfd_rx_ring *ring)
|
||||
mcp251xfd_get_rx_linear_len(const struct mcp251xfd_rx_ring *ring, u8 len)
|
||||
{
|
||||
u8 len;
|
||||
|
||||
len = mcp251xfd_get_rx_len(ring);
|
||||
|
||||
return min_t(u8, len, ring->obj_num - mcp251xfd_get_rx_tail(ring));
|
||||
}
|
||||
|
||||
@@ -926,8 +938,6 @@ void mcp251xfd_ring_free(struct mcp251xfd_priv *priv);
|
||||
int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv);
|
||||
int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv);
|
||||
int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv);
|
||||
void mcp251xfd_skb_set_timestamp(const struct mcp251xfd_priv *priv,
|
||||
struct sk_buff *skb, u32 timestamp);
|
||||
void mcp251xfd_timestamp_init(struct mcp251xfd_priv *priv);
|
||||
void mcp251xfd_timestamp_stop(struct mcp251xfd_priv *priv);
|
||||
|
||||
|
||||
@@ -86,6 +86,8 @@ struct mana_txq {
|
||||
|
||||
atomic_t pending_sends;
|
||||
|
||||
bool napi_initialized;
|
||||
|
||||
struct mana_stats_tx stats;
|
||||
};
|
||||
|
||||
|
||||
@@ -1391,10 +1391,12 @@ static void mana_destroy_txq(struct mana_port_context *apc)
|
||||
|
||||
for (i = 0; i < apc->num_queues; i++) {
|
||||
napi = &apc->tx_qp[i].tx_cq.napi;
|
||||
napi_synchronize(napi);
|
||||
napi_disable(napi);
|
||||
netif_napi_del(napi);
|
||||
|
||||
if (apc->tx_qp[i].txq.napi_initialized) {
|
||||
napi_synchronize(napi);
|
||||
napi_disable(napi);
|
||||
netif_napi_del(napi);
|
||||
apc->tx_qp[i].txq.napi_initialized = false;
|
||||
}
|
||||
mana_destroy_wq_obj(apc, GDMA_SQ, apc->tx_qp[i].tx_object);
|
||||
|
||||
mana_deinit_cq(apc, &apc->tx_qp[i].tx_cq);
|
||||
@@ -1450,6 +1452,7 @@ static int mana_create_txq(struct mana_port_context *apc,
|
||||
txq->ndev = net;
|
||||
txq->net_txq = netdev_get_tx_queue(net, i);
|
||||
txq->vp_offset = apc->tx_vp_offset;
|
||||
txq->napi_initialized = false;
|
||||
skb_queue_head_init(&txq->pending_skbs);
|
||||
|
||||
memset(&spec, 0, sizeof(spec));
|
||||
@@ -1514,6 +1517,7 @@ static int mana_create_txq(struct mana_port_context *apc,
|
||||
|
||||
netif_napi_add_tx(net, &cq->napi, mana_poll);
|
||||
napi_enable(&cq->napi);
|
||||
txq->napi_initialized = true;
|
||||
|
||||
mana_gd_ring_cq(cq->gdma_cq, SET_ARM_BIT);
|
||||
}
|
||||
@@ -1525,7 +1529,7 @@ out:
|
||||
}
|
||||
|
||||
static void mana_destroy_rxq(struct mana_port_context *apc,
|
||||
struct mana_rxq *rxq, bool validate_state)
|
||||
struct mana_rxq *rxq, bool napi_initialized)
|
||||
|
||||
{
|
||||
struct gdma_context *gc = apc->ac->gdma_dev->gdma_context;
|
||||
@@ -1539,15 +1543,15 @@ static void mana_destroy_rxq(struct mana_port_context *apc,
|
||||
|
||||
napi = &rxq->rx_cq.napi;
|
||||
|
||||
if (validate_state)
|
||||
if (napi_initialized) {
|
||||
napi_synchronize(napi);
|
||||
|
||||
napi_disable(napi);
|
||||
napi_disable(napi);
|
||||
|
||||
netif_napi_del(napi);
|
||||
}
|
||||
xdp_rxq_info_unreg(&rxq->xdp_rxq);
|
||||
|
||||
netif_napi_del(napi);
|
||||
|
||||
mana_destroy_wq_obj(apc, GDMA_RQ, rxq->rxobj);
|
||||
|
||||
mana_deinit_cq(apc, &rxq->rx_cq);
|
||||
|
||||
@@ -1816,8 +1816,10 @@ static u16 nvmet_tcp_install_queue(struct nvmet_sq *sq)
|
||||
}
|
||||
|
||||
queue->nr_cmds = sq->size * 2;
|
||||
if (nvmet_tcp_alloc_cmds(queue))
|
||||
if (nvmet_tcp_alloc_cmds(queue)) {
|
||||
queue->nr_cmds = 0;
|
||||
return NVME_SC_INTERNAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -767,7 +767,7 @@ restart:
|
||||
memcpy(name, prop->name, i);
|
||||
name[i] = '\0';
|
||||
tmp = regulator_get(dev, name);
|
||||
if (!tmp) {
|
||||
if (IS_ERR(tmp)) {
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -1553,7 +1553,6 @@ struct btrfs_drop_extents_args {
|
||||
struct btrfs_file_private {
|
||||
void *filldir_buf;
|
||||
u64 last_index;
|
||||
bool fsync_skip_inode_lock;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1534,13 +1534,6 @@ again:
|
||||
if (IS_ERR_OR_NULL(dio)) {
|
||||
err = PTR_ERR_OR_ZERO(dio);
|
||||
} else {
|
||||
struct btrfs_file_private stack_private = { 0 };
|
||||
struct btrfs_file_private *private;
|
||||
const bool have_private = (file->private_data != NULL);
|
||||
|
||||
if (!have_private)
|
||||
file->private_data = &stack_private;
|
||||
|
||||
/*
|
||||
* If we have a synchoronous write, we must make sure the fsync
|
||||
* triggered by the iomap_dio_complete() call below doesn't
|
||||
@@ -1549,13 +1542,10 @@ again:
|
||||
* partial writes due to the input buffer (or parts of it) not
|
||||
* being already faulted in.
|
||||
*/
|
||||
private = file->private_data;
|
||||
private->fsync_skip_inode_lock = true;
|
||||
ASSERT(current->journal_info == NULL);
|
||||
current->journal_info = BTRFS_TRANS_DIO_WRITE_STUB;
|
||||
err = iomap_dio_complete(dio);
|
||||
private->fsync_skip_inode_lock = false;
|
||||
|
||||
if (!have_private)
|
||||
file->private_data = NULL;
|
||||
current->journal_info = NULL;
|
||||
}
|
||||
|
||||
/* No increment (+=) because iomap returns a cumulative value. */
|
||||
@@ -1795,7 +1785,6 @@ static inline bool skip_inode_logging(const struct btrfs_log_ctx *ctx)
|
||||
*/
|
||||
int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
||||
{
|
||||
struct btrfs_file_private *private = file->private_data;
|
||||
struct dentry *dentry = file_dentry(file);
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
||||
@@ -1805,7 +1794,13 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
||||
int ret = 0, err;
|
||||
u64 len;
|
||||
bool full_sync;
|
||||
const bool skip_ilock = (private ? private->fsync_skip_inode_lock : false);
|
||||
bool skip_ilock = false;
|
||||
|
||||
if (current->journal_info == BTRFS_TRANS_DIO_WRITE_STUB) {
|
||||
skip_ilock = true;
|
||||
current->journal_info = NULL;
|
||||
lockdep_assert_held(&inode->i_rwsem);
|
||||
}
|
||||
|
||||
trace_btrfs_sync_file(file, datasync);
|
||||
|
||||
|
||||
@@ -11,6 +11,12 @@
|
||||
#include "delayed-ref.h"
|
||||
#include "ctree.h"
|
||||
|
||||
/*
|
||||
* Signal that a direct IO write is in progress, to avoid deadlock for sync
|
||||
* direct IO writes when fsync is called during the direct IO write path.
|
||||
*/
|
||||
#define BTRFS_TRANS_DIO_WRITE_STUB ((void *) 1)
|
||||
|
||||
enum btrfs_trans_state {
|
||||
TRANS_STATE_RUNNING,
|
||||
TRANS_STATE_COMMIT_START,
|
||||
|
||||
@@ -1506,7 +1506,8 @@ void fuse_send_init(struct fuse_mount *fm)
|
||||
FUSE_ABORT_ERROR | FUSE_MAX_PAGES | FUSE_CACHE_SYMLINKS |
|
||||
FUSE_NO_OPENDIR_SUPPORT | FUSE_EXPLICIT_INVAL_DATA |
|
||||
FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_EXT | FUSE_INIT_EXT |
|
||||
FUSE_SECURITY_CTX;
|
||||
FUSE_SECURITY_CTX |
|
||||
FUSE_HAS_EXPIRE_ONLY;
|
||||
#ifdef CONFIG_FUSE_DAX
|
||||
if (fm->fc->dax)
|
||||
flags |= FUSE_MAP_ALIGNMENT;
|
||||
|
||||
@@ -1392,6 +1392,7 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier)
|
||||
#define AMD_FMT_MOD_TILE_VER_GFX10 2
|
||||
#define AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS 3
|
||||
#define AMD_FMT_MOD_TILE_VER_GFX11 4
|
||||
#define AMD_FMT_MOD_TILE_VER_GFX12 5
|
||||
|
||||
/*
|
||||
* 64K_S is the same for GFX9/GFX10/GFX10_RBPLUS and hence has GFX9 as canonical
|
||||
@@ -1402,6 +1403,8 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier)
|
||||
/*
|
||||
* 64K_D for non-32 bpp is the same for GFX9/GFX10/GFX10_RBPLUS and hence has
|
||||
* GFX9 as canonical version.
|
||||
*
|
||||
* 64K_D_2D on GFX12 is identical to 64K_D on GFX11.
|
||||
*/
|
||||
#define AMD_FMT_MOD_TILE_GFX9_64K_D 10
|
||||
#define AMD_FMT_MOD_TILE_GFX9_64K_S_X 25
|
||||
@@ -1409,6 +1412,21 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier)
|
||||
#define AMD_FMT_MOD_TILE_GFX9_64K_R_X 27
|
||||
#define AMD_FMT_MOD_TILE_GFX11_256K_R_X 31
|
||||
|
||||
/* Gfx12 swizzle modes:
|
||||
* 0 - LINEAR
|
||||
* 1 - 256B_2D - 2D block dimensions
|
||||
* 2 - 4KB_2D
|
||||
* 3 - 64KB_2D
|
||||
* 4 - 256KB_2D
|
||||
* 5 - 4KB_3D - 3D block dimensions
|
||||
* 6 - 64KB_3D
|
||||
* 7 - 256KB_3D
|
||||
*/
|
||||
#define AMD_FMT_MOD_TILE_GFX12_256B_2D 1
|
||||
#define AMD_FMT_MOD_TILE_GFX12_4K_2D 2
|
||||
#define AMD_FMT_MOD_TILE_GFX12_64K_2D 3
|
||||
#define AMD_FMT_MOD_TILE_GFX12_256K_2D 4
|
||||
|
||||
#define AMD_FMT_MOD_DCC_BLOCK_64B 0
|
||||
#define AMD_FMT_MOD_DCC_BLOCK_128B 1
|
||||
#define AMD_FMT_MOD_DCC_BLOCK_256B 2
|
||||
|
||||
@@ -365,6 +365,7 @@ struct fuse_file_lock {
|
||||
* FUSE_SECURITY_CTX: add security context to create, mkdir, symlink, and
|
||||
* mknod
|
||||
* FUSE_HAS_INODE_DAX: use per inode DAX
|
||||
* FUSE_HAS_EXPIRE_ONLY: kernel supports expiry-only entry invalidation
|
||||
*/
|
||||
#define FUSE_ASYNC_READ (1 << 0)
|
||||
#define FUSE_POSIX_LOCKS (1 << 1)
|
||||
@@ -401,6 +402,7 @@ struct fuse_file_lock {
|
||||
/* bits 32..63 get shifted down 32 bits into the flags2 field */
|
||||
#define FUSE_SECURITY_CTX (1ULL << 32)
|
||||
#define FUSE_HAS_INODE_DAX (1ULL << 33)
|
||||
#define FUSE_HAS_EXPIRE_ONLY (1ULL << 35)
|
||||
|
||||
/*
|
||||
* For FUSE < 7.36 FUSE_PASSTHROUGH has value (1 << 31).
|
||||
|
||||
@@ -467,10 +467,16 @@ static bool btf_type_is_fwd(const struct btf_type *t)
|
||||
return BTF_INFO_KIND(t->info) == BTF_KIND_FWD;
|
||||
}
|
||||
|
||||
static bool btf_type_is_decl_tag(const struct btf_type *t)
|
||||
{
|
||||
return BTF_INFO_KIND(t->info) == BTF_KIND_DECL_TAG;
|
||||
}
|
||||
|
||||
static bool btf_type_nosize(const struct btf_type *t)
|
||||
{
|
||||
return btf_type_is_void(t) || btf_type_is_fwd(t) ||
|
||||
btf_type_is_func(t) || btf_type_is_func_proto(t);
|
||||
btf_type_is_func(t) || btf_type_is_func_proto(t) ||
|
||||
btf_type_is_decl_tag(t);
|
||||
}
|
||||
|
||||
static bool btf_type_nosize_or_null(const struct btf_type *t)
|
||||
@@ -493,11 +499,6 @@ static bool btf_type_is_datasec(const struct btf_type *t)
|
||||
return BTF_INFO_KIND(t->info) == BTF_KIND_DATASEC;
|
||||
}
|
||||
|
||||
static bool btf_type_is_decl_tag(const struct btf_type *t)
|
||||
{
|
||||
return BTF_INFO_KIND(t->info) == BTF_KIND_DECL_TAG;
|
||||
}
|
||||
|
||||
static bool btf_type_is_decl_tag_target(const struct btf_type *t)
|
||||
{
|
||||
return btf_type_is_func(t) || btf_type_is_struct(t) ||
|
||||
|
||||
@@ -5896,10 +5896,18 @@ static void wq_watchdog_timer_fn(struct timer_list *unused)
|
||||
|
||||
notrace void wq_watchdog_touch(int cpu)
|
||||
{
|
||||
if (cpu >= 0)
|
||||
per_cpu(wq_watchdog_touched_cpu, cpu) = jiffies;
|
||||
unsigned long thresh = READ_ONCE(wq_watchdog_thresh) * HZ;
|
||||
unsigned long touch_ts = READ_ONCE(wq_watchdog_touched);
|
||||
unsigned long now = jiffies;
|
||||
|
||||
wq_watchdog_touched = jiffies;
|
||||
if (cpu >= 0)
|
||||
per_cpu(wq_watchdog_touched_cpu, cpu) = now;
|
||||
else
|
||||
WARN_ONCE(1, "%s should be called with valid CPU", __func__);
|
||||
|
||||
/* Don't unnecessarily store to global cacheline */
|
||||
if (time_after(now, touch_ts + thresh / 4))
|
||||
WRITE_ONCE(wq_watchdog_touched, jiffies);
|
||||
}
|
||||
|
||||
static void wq_watchdog_set_thresh(unsigned long thresh)
|
||||
|
||||
@@ -5156,12 +5156,29 @@ static struct cftype mem_cgroup_legacy_files[] = {
|
||||
*/
|
||||
|
||||
static DEFINE_IDR(mem_cgroup_idr);
|
||||
static DEFINE_SPINLOCK(memcg_idr_lock);
|
||||
|
||||
static int mem_cgroup_alloc_id(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
idr_preload(GFP_KERNEL);
|
||||
spin_lock(&memcg_idr_lock);
|
||||
ret = idr_alloc(&mem_cgroup_idr, NULL, 1, MEM_CGROUP_ID_MAX + 1,
|
||||
GFP_NOWAIT);
|
||||
spin_unlock(&memcg_idr_lock);
|
||||
idr_preload_end();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mem_cgroup_id_remove(struct mem_cgroup *memcg)
|
||||
{
|
||||
if (memcg->id.id > 0) {
|
||||
trace_android_vh_mem_cgroup_id_remove(memcg);
|
||||
spin_lock(&memcg_idr_lock);
|
||||
idr_remove(&mem_cgroup_idr, memcg->id.id);
|
||||
spin_unlock(&memcg_idr_lock);
|
||||
|
||||
memcg->id.id = 0;
|
||||
}
|
||||
}
|
||||
@@ -5286,8 +5303,7 @@ static struct mem_cgroup *mem_cgroup_alloc(void)
|
||||
if (!memcg)
|
||||
return ERR_PTR(error);
|
||||
|
||||
memcg->id.id = idr_alloc(&mem_cgroup_idr, NULL,
|
||||
1, MEM_CGROUP_ID_MAX + 1, GFP_KERNEL);
|
||||
memcg->id.id = mem_cgroup_alloc_id();
|
||||
if (memcg->id.id < 0) {
|
||||
error = memcg->id.id;
|
||||
goto fail;
|
||||
@@ -5332,7 +5348,9 @@ static struct mem_cgroup *mem_cgroup_alloc(void)
|
||||
INIT_LIST_HEAD(&memcg->deferred_split_queue.split_queue);
|
||||
memcg->deferred_split_queue.split_queue_len = 0;
|
||||
#endif
|
||||
spin_lock(&memcg_idr_lock);
|
||||
idr_replace(&mem_cgroup_idr, memcg, memcg->id.id);
|
||||
spin_unlock(&memcg_idr_lock);
|
||||
lru_gen_init_memcg(memcg);
|
||||
trace_android_vh_mem_cgroup_alloc(memcg);
|
||||
return memcg;
|
||||
|
||||
@@ -1817,6 +1817,8 @@ static int sof_link_unload(struct snd_soc_component *scomp, struct snd_soc_dobj
|
||||
if (!slink)
|
||||
return 0;
|
||||
|
||||
slink->link->platforms->name = NULL;
|
||||
|
||||
kfree(slink->tuples);
|
||||
list_del(&slink->list);
|
||||
kfree(slink->hw_configs);
|
||||
|
||||
@@ -100,8 +100,8 @@
|
||||
#define SUN8I_I2S_CTRL_MODE_PCM (0 << 4)
|
||||
|
||||
#define SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK BIT(19)
|
||||
#define SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED (1 << 19)
|
||||
#define SUN8I_I2S_FMT0_LRCLK_POLARITY_NORMAL (0 << 19)
|
||||
#define SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH (1 << 19)
|
||||
#define SUN8I_I2S_FMT0_LRCLK_POLARITY_START_LOW (0 << 19)
|
||||
#define SUN8I_I2S_FMT0_LRCK_PERIOD_MASK GENMASK(17, 8)
|
||||
#define SUN8I_I2S_FMT0_LRCK_PERIOD(period) ((period - 1) << 8)
|
||||
#define SUN8I_I2S_FMT0_BCLK_POLARITY_MASK BIT(7)
|
||||
@@ -727,65 +727,37 @@ static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
|
||||
static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
|
||||
unsigned int fmt)
|
||||
{
|
||||
u32 mode, val;
|
||||
u32 mode, lrclk_pol, bclk_pol, val;
|
||||
u8 offset;
|
||||
|
||||
/*
|
||||
* DAI clock polarity
|
||||
*
|
||||
* The setup for LRCK contradicts the datasheet, but under a
|
||||
* scope it's clear that the LRCK polarity is reversed
|
||||
* compared to the expected polarity on the bus.
|
||||
*/
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_IB_IF:
|
||||
/* Invert both clocks */
|
||||
val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
/* Invert bit clock */
|
||||
val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED |
|
||||
SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_IF:
|
||||
/* Invert frame clock */
|
||||
val = 0;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
|
||||
SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK |
|
||||
SUN8I_I2S_FMT0_BCLK_POLARITY_MASK,
|
||||
val);
|
||||
|
||||
/* DAI Mode */
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;
|
||||
mode = SUN8I_I2S_CTRL_MODE_PCM;
|
||||
offset = 1;
|
||||
break;
|
||||
|
||||
case SND_SOC_DAIFMT_DSP_B:
|
||||
lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;
|
||||
mode = SUN8I_I2S_CTRL_MODE_PCM;
|
||||
offset = 0;
|
||||
break;
|
||||
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_LOW;
|
||||
mode = SUN8I_I2S_CTRL_MODE_LEFT;
|
||||
offset = 1;
|
||||
break;
|
||||
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;
|
||||
mode = SUN8I_I2S_CTRL_MODE_LEFT;
|
||||
offset = 0;
|
||||
break;
|
||||
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;
|
||||
mode = SUN8I_I2S_CTRL_MODE_RIGHT;
|
||||
offset = 0;
|
||||
break;
|
||||
@@ -803,6 +775,35 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
|
||||
SUN8I_I2S_TX_CHAN_OFFSET_MASK,
|
||||
SUN8I_I2S_TX_CHAN_OFFSET(offset));
|
||||
|
||||
/* DAI clock polarity */
|
||||
bclk_pol = SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL;
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_IB_IF:
|
||||
/* Invert both clocks */
|
||||
lrclk_pol ^= SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK;
|
||||
bclk_pol = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
/* Invert bit clock */
|
||||
bclk_pol = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_IF:
|
||||
/* Invert frame clock */
|
||||
lrclk_pol ^= SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
/* No inversion */
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
|
||||
SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK |
|
||||
SUN8I_I2S_FMT0_BCLK_POLARITY_MASK,
|
||||
lrclk_pol | bclk_pol);
|
||||
|
||||
/* DAI clock master masks */
|
||||
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
|
||||
case SND_SOC_DAIFMT_BP_FP:
|
||||
@@ -834,65 +835,37 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
|
||||
static int sun50i_h6_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
|
||||
unsigned int fmt)
|
||||
{
|
||||
u32 mode, val;
|
||||
u32 mode, lrclk_pol, bclk_pol, val;
|
||||
u8 offset;
|
||||
|
||||
/*
|
||||
* DAI clock polarity
|
||||
*
|
||||
* The setup for LRCK contradicts the datasheet, but under a
|
||||
* scope it's clear that the LRCK polarity is reversed
|
||||
* compared to the expected polarity on the bus.
|
||||
*/
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_IB_IF:
|
||||
/* Invert both clocks */
|
||||
val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
/* Invert bit clock */
|
||||
val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED |
|
||||
SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_IF:
|
||||
/* Invert frame clock */
|
||||
val = 0;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
|
||||
SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK |
|
||||
SUN8I_I2S_FMT0_BCLK_POLARITY_MASK,
|
||||
val);
|
||||
|
||||
/* DAI Mode */
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;
|
||||
mode = SUN8I_I2S_CTRL_MODE_PCM;
|
||||
offset = 1;
|
||||
break;
|
||||
|
||||
case SND_SOC_DAIFMT_DSP_B:
|
||||
lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;
|
||||
mode = SUN8I_I2S_CTRL_MODE_PCM;
|
||||
offset = 0;
|
||||
break;
|
||||
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_LOW;
|
||||
mode = SUN8I_I2S_CTRL_MODE_LEFT;
|
||||
offset = 1;
|
||||
break;
|
||||
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;
|
||||
mode = SUN8I_I2S_CTRL_MODE_LEFT;
|
||||
offset = 0;
|
||||
break;
|
||||
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;
|
||||
mode = SUN8I_I2S_CTRL_MODE_RIGHT;
|
||||
offset = 0;
|
||||
break;
|
||||
@@ -910,6 +883,36 @@ static int sun50i_h6_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
|
||||
SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK,
|
||||
SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset));
|
||||
|
||||
/* DAI clock polarity */
|
||||
bclk_pol = SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL;
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_IB_IF:
|
||||
/* Invert both clocks */
|
||||
lrclk_pol ^= SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK;
|
||||
bclk_pol = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
/* Invert bit clock */
|
||||
bclk_pol = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_IF:
|
||||
/* Invert frame clock */
|
||||
lrclk_pol ^= SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
/* No inversion */
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
|
||||
SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK |
|
||||
SUN8I_I2S_FMT0_BCLK_POLARITY_MASK,
|
||||
lrclk_pol | bclk_pol);
|
||||
|
||||
|
||||
/* DAI clock master masks */
|
||||
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
|
||||
case SND_SOC_DAIFMT_BP_FP:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// tegra210_ahub.c - Tegra210 AHUB driver
|
||||
//
|
||||
// Copyright (c) 2020-2022, NVIDIA CORPORATION. All rights reserved.
|
||||
// Copyright (c) 2020-2024, NVIDIA CORPORATION. All rights reserved.
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
@@ -1401,12 +1401,14 @@ static int tegra_ahub_probe(struct platform_device *pdev)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
err = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
|
||||
if (err) {
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user