This is the 5.4.6 stable release
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEZH8oZUiU471FcZm+ONu9yGCSaT4FAl397mMACgkQONu9yGCS aT4pqxAAu5o3/xNNdKcfR6GkobAEHq/62MuBpQmqt3Ii8G9JSleASQmsYyZZVHI6 JiMrmWiULJ1T2R8lUz8Li2PumIvmPSaW6H9VjiaaGz6U8XSJZzrxhgdNkibz4uzJ JhNaikLo4mWz3p/O7OkvFoHjMGmgc3m2rjuukMOUokQCQFYMrKms8FjFzKHk/87H RfvIHtwcvL6aVv3BzHXC8od3mC69uE56+zdB9lBYPeH38EjShtcd58jsnLYusSnM BqFChcYqHC5WHZ8WfWcLmcmgkaKotoxzhgX/YUpXo1pScfxht3rHqE0h/XB/aPFR U8V7gT1af0cbumB7bHDKje7ROyPQUoxrrsZtYYct0DS831sAFTfiTac4NlyElnIv PgknutRdK3FwD+GjI5BCHveGyiucKQhet+qTglzg8J942PQjdy7Bl8tIV2smqHrA 0/I66jcusr1G7leD/QjAc8Sli6tX9LJslW/SJXlgdxdfQ9bptRnl8aOfh3ZQILOS lqCm297APCi4bVS4YFrLg6kc+FPMtAW7+oIXarbhNtxgW1P9vuNOhS0c7qRH/51i j6WPjqfJA0itcKI3bZUlaZR6kzKhkgTnvy6phIxMpaQxdkNh+vuBvLzK/dP9o0Hv sgZ+fcAZjqzAKjOFJ1kXBNv9AN2mGKN9cw+6zvngcybMv9aKUWk= =V0vt -----END PGP SIGNATURE----- Merge 5.4.6 into android-5.4 Changes in 5.4.6 USB: Fix incorrect DMA allocations for local memory pool drivers mmc: block: Make card_busy_detect() a bit more generic mmc: block: Add CMD13 polling for MMC IOCTLS with R1B response mmc: core: Drop check for mmc_card_is_removable() in mmc_rescan() mmc: core: Re-work HW reset for SDIO cards PCI/switchtec: Read all 64 bits of part_event_bitmap PCI/PM: Always return devices to D0 when thawing PCI: pciehp: Avoid returning prematurely from sysfs requests PCI: Fix Intel ACS quirk UPDCR register address PCI/MSI: Fix incorrect MSI-X masking on resume PCI: Do not use bus number zero from EA capability PCI: rcar: Fix missing MACCTLR register setting in initialization sequence PCI: Apply Cavium ACS quirk to ThunderX2 and ThunderX3 PM / QoS: Redefine FREQ_QOS_MAX_DEFAULT_VALUE to S32_MAX block: fix "check bi_size overflow before merge" xtensa: use MEMBLOCK_ALLOC_ANYWHERE for KASAN shadow map gfs2: Multi-block allocations in gfs2_page_mkwrite gfs2: fix glock reference problem in gfs2_trans_remove_revoke xtensa: fix TLB sanity checker xtensa: fix syscall_set_return_value rpmsg: glink: Set tail pointer to 0 at end of FIFO rpmsg: glink: Fix reuse intents memory leak issue rpmsg: glink: Fix use after free in open_ack TIMEOUT case rpmsg: glink: Put an extra reference during cleanup rpmsg: glink: Fix rpmsg_register_device err handling rpmsg: glink: Don't send pending rx_done during remove rpmsg: glink: Free pending deferred work on remove cifs: smbd: Return -EAGAIN when transport is reconnecting cifs: smbd: Only queue work for error recovery on memory registration cifs: smbd: Add messages on RDMA session destroy and reconnection cifs: smbd: Return -EINVAL when the number of iovs exceeds SMBDIRECT_MAX_SGE cifs: smbd: Return -ECONNABORTED when trasnport is not in connected state cifs: Don't display RDMA transport on reconnect CIFS: Respect O_SYNC and O_DIRECT flags during reconnect CIFS: Close open handle after interrupted close CIFS: Do not miss cancelled OPEN responses CIFS: Fix NULL pointer dereference in mid callback cifs: Fix retrieval of DFS referrals in cifs_mount() ARM: dts: s3c64xx: Fix init order of clock providers ARM: tegra: Fix FLOW_CTLR_HALT register clobbering by tegra_resume() vfio/pci: call irq_bypass_unregister_producer() before freeing irq dma-buf: Fix memory leak in sync_file_merge() drm/panfrost: Fix a race in panfrost_ioctl_madvise() drm/panfrost: Fix a BO leak in panfrost_ioctl_mmap_bo() drm/panfrost: Fix a race in panfrost_gem_free_object() drm/mgag200: Extract device type from flags drm/mgag200: Store flags from PCI driver data in device structure drm/mgag200: Add workaround for HW that does not support 'startadd' drm/mgag200: Flag all G200 SE A machines as broken wrt <startadd> drm: meson: venc: cvbs: fix CVBS mode matching dm mpath: remove harmful bio-based optimization dm btree: increase rebalance threshold in __rebalance2() dm clone metadata: Track exact changes per transaction dm clone metadata: Use a two phase commit dm clone: Flush destination device before committing metadata dm thin metadata: Add support for a pre-commit callback dm thin: Flush data device before committing metadata scsi: ufs: Disable autohibern8 feature in Cadence UFS scsi: iscsi: Fix a potential deadlock in the timeout handler scsi: qla2xxx: Ignore NULL pointer in tcm_qla2xxx_free_mcmd scsi: qla2xxx: Initialize free_work before flushing it scsi: qla2xxx: Added support for MPI and PEP regions for ISP28XX scsi: qla2xxx: Change discovery state before PLOGI scsi: qla2xxx: Correctly retrieve and interpret active flash region scsi: qla2xxx: Fix incorrect SFUB length used for Secure Flash Update MB Cmd drm/nouveau/kms/nv50-: Call outp_atomic_check_view() before handling PBN drm/nouveau/kms/nv50-: Store the bpc we're using in nv50_head_atom drm/nouveau/kms/nv50-: Limit MST BPC to 8 drm/i915/fbc: Disable fbc by default on all glk+ drm/radeon: fix r1xx/r2xx register checker for POT textures drm/dp_mst: Correct the bug in drm_dp_update_payload_part1() drm/amd/display: re-enable wait in pipelock, but add timeout drm/amd/display: add default clocks if not able to fetch them drm/amdgpu: initialize vm_inv_eng0_sem for gfxhub and mmhub drm/amdgpu: invalidate mmhub semaphore workaround in gmc9/gmc10 drm/amdgpu/gfx10: explicitly wait for cp idle after halt/unhalt drm/amdgpu/gfx10: re-init clear state buffer after gpu reset drm/i915/gvt: Fix cmd length check for MI_ATOMIC drm/amdgpu: avoid using invalidate semaphore for picasso drm/amdgpu: add invalidate semaphore limit for SRIOV and picasso in gmc9 ALSA: hda: Fix regression by strip mask fix Linux 5.4.6 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: Ieb34254e2c00cee10d0012aaaf8fef323280c04f
This commit is contained in:
commit
63dd580f09
2
Makefile
2
Makefile
@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
VERSION = 5
|
||||
PATCHLEVEL = 4
|
||||
SUBLEVEL = 5
|
||||
SUBLEVEL = 6
|
||||
EXTRAVERSION =
|
||||
NAME = Kleptomaniac Octopus
|
||||
|
||||
|
@ -165,6 +165,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
&clocks {
|
||||
clocks = <&fin_pll>;
|
||||
};
|
||||
|
||||
&sdhci0 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&sd0_clk>, <&sd0_cmd>, <&sd0_cd>, <&sd0_bus4>;
|
||||
|
@ -69,6 +69,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
&clocks {
|
||||
clocks = <&fin_pll>;
|
||||
};
|
||||
|
||||
&sdhci0 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&sd0_clk>, <&sd0_cmd>, <&sd0_cd>, <&sd0_bus4>;
|
||||
|
@ -44,16 +44,16 @@ ENTRY(tegra_resume)
|
||||
cmp r6, #TEGRA20
|
||||
beq 1f @ Yes
|
||||
/* Clear the flow controller flags for this CPU. */
|
||||
cpu_to_csr_reg r1, r0
|
||||
cpu_to_csr_reg r3, r0
|
||||
mov32 r2, TEGRA_FLOW_CTRL_BASE
|
||||
ldr r1, [r2, r1]
|
||||
ldr r1, [r2, r3]
|
||||
/* Clear event & intr flag */
|
||||
orr r1, r1, \
|
||||
#FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
|
||||
movw r0, #0x3FFD @ enable, cluster_switch, immed, bitmaps
|
||||
@ & ext flags for CPU power mgnt
|
||||
bic r1, r1, r0
|
||||
str r1, [r2]
|
||||
str r1, [r2, r3]
|
||||
1:
|
||||
|
||||
mov32 r9, 0xc09
|
||||
|
@ -51,7 +51,7 @@ static inline void syscall_set_return_value(struct task_struct *task,
|
||||
struct pt_regs *regs,
|
||||
int error, long val)
|
||||
{
|
||||
regs->areg[0] = (long) error ? error : val;
|
||||
regs->areg[2] = (long) error ? error : val;
|
||||
}
|
||||
|
||||
#define SYSCALL_MAX_ARGS 6
|
||||
|
@ -56,7 +56,9 @@ static void __init populate(void *start, void *end)
|
||||
|
||||
for (k = 0; k < PTRS_PER_PTE; ++k, ++j) {
|
||||
phys_addr_t phys =
|
||||
memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE);
|
||||
memblock_phys_alloc_range(PAGE_SIZE, PAGE_SIZE,
|
||||
0,
|
||||
MEMBLOCK_ALLOC_ANYWHERE);
|
||||
|
||||
if (!phys)
|
||||
panic("Failed to allocate page table page\n");
|
||||
|
@ -216,6 +216,8 @@ static int check_tlb_entry(unsigned w, unsigned e, bool dtlb)
|
||||
unsigned tlbidx = w | (e << PAGE_SHIFT);
|
||||
unsigned r0 = dtlb ?
|
||||
read_dtlb_virtual(tlbidx) : read_itlb_virtual(tlbidx);
|
||||
unsigned r1 = dtlb ?
|
||||
read_dtlb_translation(tlbidx) : read_itlb_translation(tlbidx);
|
||||
unsigned vpn = (r0 & PAGE_MASK) | (e << PAGE_SHIFT);
|
||||
unsigned pte = get_pte_for_vaddr(vpn);
|
||||
unsigned mm_asid = (get_rasid_register() >> 8) & ASID_MASK;
|
||||
@ -231,8 +233,6 @@ static int check_tlb_entry(unsigned w, unsigned e, bool dtlb)
|
||||
}
|
||||
|
||||
if (tlb_asid == mm_asid) {
|
||||
unsigned r1 = dtlb ? read_dtlb_translation(tlbidx) :
|
||||
read_itlb_translation(tlbidx);
|
||||
if ((pte ^ r1) & PAGE_MASK) {
|
||||
pr_err("%cTLB: way: %u, entry: %u, mapping: %08x->%08x, PTE: %08x\n",
|
||||
dtlb ? 'D' : 'I', w, e, r0, r1, pte);
|
||||
|
@ -753,10 +753,12 @@ bool __bio_try_merge_page(struct bio *bio, struct page *page,
|
||||
if (WARN_ON_ONCE(bio_flagged(bio, BIO_CLONED)))
|
||||
return false;
|
||||
|
||||
if (bio->bi_vcnt > 0 && !bio_full(bio, len)) {
|
||||
if (bio->bi_vcnt > 0) {
|
||||
struct bio_vec *bv = &bio->bi_io_vec[bio->bi_vcnt - 1];
|
||||
|
||||
if (page_is_mergeable(bv, page, len, off, same_page)) {
|
||||
if (bio->bi_iter.bi_size > UINT_MAX - len)
|
||||
return false;
|
||||
bv->bv_len += len;
|
||||
bio->bi_iter.bi_size += len;
|
||||
return true;
|
||||
|
@ -221,7 +221,7 @@ static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
|
||||
a_fences = get_fences(a, &a_num_fences);
|
||||
b_fences = get_fences(b, &b_num_fences);
|
||||
if (a_num_fences > INT_MAX - b_num_fences)
|
||||
return NULL;
|
||||
goto err;
|
||||
|
||||
num_fences = a_num_fences + b_num_fences;
|
||||
|
||||
|
@ -77,6 +77,7 @@ struct amdgpu_gmc_fault {
|
||||
struct amdgpu_vmhub {
|
||||
uint32_t ctx0_ptb_addr_lo32;
|
||||
uint32_t ctx0_ptb_addr_hi32;
|
||||
uint32_t vm_inv_eng0_sem;
|
||||
uint32_t vm_inv_eng0_req;
|
||||
uint32_t vm_inv_eng0_ack;
|
||||
uint32_t vm_context0_cntl;
|
||||
|
@ -1785,27 +1785,52 @@ static void gfx_v10_0_enable_gui_idle_interrupt(struct amdgpu_device *adev,
|
||||
WREG32_SOC15(GC, 0, mmCP_INT_CNTL_RING0, tmp);
|
||||
}
|
||||
|
||||
static void gfx_v10_0_init_csb(struct amdgpu_device *adev)
|
||||
static int gfx_v10_0_init_csb(struct amdgpu_device *adev)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (adev->in_gpu_reset) {
|
||||
r = amdgpu_bo_reserve(adev->gfx.rlc.clear_state_obj, false);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = amdgpu_bo_kmap(adev->gfx.rlc.clear_state_obj,
|
||||
(void **)&adev->gfx.rlc.cs_ptr);
|
||||
if (!r) {
|
||||
adev->gfx.rlc.funcs->get_csb_buffer(adev,
|
||||
adev->gfx.rlc.cs_ptr);
|
||||
amdgpu_bo_kunmap(adev->gfx.rlc.clear_state_obj);
|
||||
}
|
||||
|
||||
amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* csib */
|
||||
WREG32_SOC15(GC, 0, mmRLC_CSIB_ADDR_HI,
|
||||
adev->gfx.rlc.clear_state_gpu_addr >> 32);
|
||||
WREG32_SOC15(GC, 0, mmRLC_CSIB_ADDR_LO,
|
||||
adev->gfx.rlc.clear_state_gpu_addr & 0xfffffffc);
|
||||
WREG32_SOC15(GC, 0, mmRLC_CSIB_LENGTH, adev->gfx.rlc.clear_state_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gfx_v10_0_init_pg(struct amdgpu_device *adev)
|
||||
static int gfx_v10_0_init_pg(struct amdgpu_device *adev)
|
||||
{
|
||||
int i;
|
||||
int r;
|
||||
|
||||
gfx_v10_0_init_csb(adev);
|
||||
r = gfx_v10_0_init_csb(adev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
for (i = 0; i < adev->num_vmhubs; i++)
|
||||
amdgpu_gmc_flush_gpu_tlb(adev, 0, i, 0);
|
||||
|
||||
/* TODO: init power gating */
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gfx_v10_0_rlc_stop(struct amdgpu_device *adev)
|
||||
@ -1907,7 +1932,10 @@ static int gfx_v10_0_rlc_resume(struct amdgpu_device *adev)
|
||||
r = gfx_v10_0_wait_for_rlc_autoload_complete(adev);
|
||||
if (r)
|
||||
return r;
|
||||
gfx_v10_0_init_pg(adev);
|
||||
|
||||
r = gfx_v10_0_init_pg(adev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/* enable RLC SRM */
|
||||
gfx_v10_0_rlc_enable_srm(adev);
|
||||
@ -1933,7 +1961,10 @@ static int gfx_v10_0_rlc_resume(struct amdgpu_device *adev)
|
||||
return r;
|
||||
}
|
||||
|
||||
gfx_v10_0_init_pg(adev);
|
||||
r = gfx_v10_0_init_pg(adev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
adev->gfx.rlc.funcs->start(adev);
|
||||
|
||||
if (adev->firmware.load_type == AMDGPU_FW_LOAD_RLC_BACKDOOR_AUTO) {
|
||||
@ -2400,7 +2431,7 @@ static int gfx_v10_0_wait_for_rlc_autoload_complete(struct amdgpu_device *adev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gfx_v10_0_cp_gfx_enable(struct amdgpu_device *adev, bool enable)
|
||||
static int gfx_v10_0_cp_gfx_enable(struct amdgpu_device *adev, bool enable)
|
||||
{
|
||||
int i;
|
||||
u32 tmp = RREG32_SOC15(GC, 0, mmCP_ME_CNTL);
|
||||
@ -2413,7 +2444,17 @@ static void gfx_v10_0_cp_gfx_enable(struct amdgpu_device *adev, bool enable)
|
||||
adev->gfx.gfx_ring[i].sched.ready = false;
|
||||
}
|
||||
WREG32_SOC15(GC, 0, mmCP_ME_CNTL, tmp);
|
||||
udelay(50);
|
||||
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
if (RREG32_SOC15(GC, 0, mmCP_STAT) == 0)
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i >= adev->usec_timeout)
|
||||
DRM_ERROR("failed to %s cp gfx\n", enable ? "unhalt" : "halt");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gfx_v10_0_cp_gfx_load_pfp_microcode(struct amdgpu_device *adev)
|
||||
|
@ -365,6 +365,8 @@ void gfxhub_v1_0_init(struct amdgpu_device *adev)
|
||||
hub->ctx0_ptb_addr_hi32 =
|
||||
SOC15_REG_OFFSET(GC, 0,
|
||||
mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32);
|
||||
hub->vm_inv_eng0_sem =
|
||||
SOC15_REG_OFFSET(GC, 0, mmVM_INVALIDATE_ENG0_SEM);
|
||||
hub->vm_inv_eng0_req =
|
||||
SOC15_REG_OFFSET(GC, 0, mmVM_INVALIDATE_ENG0_REQ);
|
||||
hub->vm_inv_eng0_ack =
|
||||
|
@ -350,6 +350,8 @@ void gfxhub_v2_0_init(struct amdgpu_device *adev)
|
||||
hub->ctx0_ptb_addr_hi32 =
|
||||
SOC15_REG_OFFSET(GC, 0,
|
||||
mmGCVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32);
|
||||
hub->vm_inv_eng0_sem =
|
||||
SOC15_REG_OFFSET(GC, 0, mmGCVM_INVALIDATE_ENG0_SEM);
|
||||
hub->vm_inv_eng0_req =
|
||||
SOC15_REG_OFFSET(GC, 0, mmGCVM_INVALIDATE_ENG0_REQ);
|
||||
hub->vm_inv_eng0_ack =
|
||||
|
@ -235,6 +235,29 @@ static void gmc_v10_0_flush_vm_hub(struct amdgpu_device *adev, uint32_t vmid,
|
||||
const unsigned eng = 17;
|
||||
unsigned int i;
|
||||
|
||||
spin_lock(&adev->gmc.invalidate_lock);
|
||||
/*
|
||||
* It may lose gpuvm invalidate acknowldege state across power-gating
|
||||
* off cycle, add semaphore acquire before invalidation and semaphore
|
||||
* release after invalidation to avoid entering power gated state
|
||||
* to WA the Issue
|
||||
*/
|
||||
|
||||
/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
|
||||
if (vmhub == AMDGPU_MMHUB_0 ||
|
||||
vmhub == AMDGPU_MMHUB_1) {
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
/* a read return value of 1 means semaphore acuqire */
|
||||
tmp = RREG32_NO_KIQ(hub->vm_inv_eng0_sem + eng);
|
||||
if (tmp & 0x1)
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i >= adev->usec_timeout)
|
||||
DRM_ERROR("Timeout waiting for sem acquire in VM flush!\n");
|
||||
}
|
||||
|
||||
WREG32_NO_KIQ(hub->vm_inv_eng0_req + eng, tmp);
|
||||
|
||||
/*
|
||||
@ -254,6 +277,17 @@ static void gmc_v10_0_flush_vm_hub(struct amdgpu_device *adev, uint32_t vmid,
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
|
||||
if (vmhub == AMDGPU_MMHUB_0 ||
|
||||
vmhub == AMDGPU_MMHUB_1)
|
||||
/*
|
||||
* add semaphore release after invalidation,
|
||||
* write with 0 means semaphore release
|
||||
*/
|
||||
WREG32_NO_KIQ(hub->vm_inv_eng0_sem + eng, 0);
|
||||
|
||||
spin_unlock(&adev->gmc.invalidate_lock);
|
||||
|
||||
if (i < adev->usec_timeout)
|
||||
return;
|
||||
|
||||
@ -338,6 +372,20 @@ static uint64_t gmc_v10_0_emit_flush_gpu_tlb(struct amdgpu_ring *ring,
|
||||
uint32_t req = gmc_v10_0_get_invalidate_req(vmid, 0);
|
||||
unsigned eng = ring->vm_inv_eng;
|
||||
|
||||
/*
|
||||
* It may lose gpuvm invalidate acknowldege state across power-gating
|
||||
* off cycle, add semaphore acquire before invalidation and semaphore
|
||||
* release after invalidation to avoid entering power gated state
|
||||
* to WA the Issue
|
||||
*/
|
||||
|
||||
/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
|
||||
if (ring->funcs->vmhub == AMDGPU_MMHUB_0 ||
|
||||
ring->funcs->vmhub == AMDGPU_MMHUB_1)
|
||||
/* a read return value of 1 means semaphore acuqire */
|
||||
amdgpu_ring_emit_reg_wait(ring,
|
||||
hub->vm_inv_eng0_sem + eng, 0x1, 0x1);
|
||||
|
||||
amdgpu_ring_emit_wreg(ring, hub->ctx0_ptb_addr_lo32 + (2 * vmid),
|
||||
lower_32_bits(pd_addr));
|
||||
|
||||
@ -348,6 +396,15 @@ static uint64_t gmc_v10_0_emit_flush_gpu_tlb(struct amdgpu_ring *ring,
|
||||
hub->vm_inv_eng0_ack + eng,
|
||||
req, 1 << vmid);
|
||||
|
||||
/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
|
||||
if (ring->funcs->vmhub == AMDGPU_MMHUB_0 ||
|
||||
ring->funcs->vmhub == AMDGPU_MMHUB_1)
|
||||
/*
|
||||
* add semaphore release after invalidation,
|
||||
* write with 0 means semaphore release
|
||||
*/
|
||||
amdgpu_ring_emit_wreg(ring, hub->vm_inv_eng0_sem + eng, 0);
|
||||
|
||||
return pd_addr;
|
||||
}
|
||||
|
||||
|
@ -448,6 +448,24 @@ static uint32_t gmc_v9_0_get_invalidate_req(unsigned int vmid,
|
||||
return req;
|
||||
}
|
||||
|
||||
/**
|
||||
* gmc_v9_0_use_invalidate_semaphore - judge whether to use semaphore
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @vmhub: vmhub type
|
||||
*
|
||||
*/
|
||||
static bool gmc_v9_0_use_invalidate_semaphore(struct amdgpu_device *adev,
|
||||
uint32_t vmhub)
|
||||
{
|
||||
return ((vmhub == AMDGPU_MMHUB_0 ||
|
||||
vmhub == AMDGPU_MMHUB_1) &&
|
||||
(!amdgpu_sriov_vf(adev)) &&
|
||||
(!(adev->asic_type == CHIP_RAVEN &&
|
||||
adev->rev_id < 0x8 &&
|
||||
adev->pdev->device == 0x15d8)));
|
||||
}
|
||||
|
||||
/*
|
||||
* GART
|
||||
* VMID 0 is the physical GPU addresses as used by the kernel.
|
||||
@ -467,6 +485,7 @@ static uint32_t gmc_v9_0_get_invalidate_req(unsigned int vmid,
|
||||
static void gmc_v9_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid,
|
||||
uint32_t vmhub, uint32_t flush_type)
|
||||
{
|
||||
bool use_semaphore = gmc_v9_0_use_invalidate_semaphore(adev, vmhub);
|
||||
const unsigned eng = 17;
|
||||
u32 j, tmp;
|
||||
struct amdgpu_vmhub *hub;
|
||||
@ -491,6 +510,28 @@ static void gmc_v9_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid,
|
||||
}
|
||||
|
||||
spin_lock(&adev->gmc.invalidate_lock);
|
||||
|
||||
/*
|
||||
* It may lose gpuvm invalidate acknowldege state across power-gating
|
||||
* off cycle, add semaphore acquire before invalidation and semaphore
|
||||
* release after invalidation to avoid entering power gated state
|
||||
* to WA the Issue
|
||||
*/
|
||||
|
||||
/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
|
||||
if (use_semaphore) {
|
||||
for (j = 0; j < adev->usec_timeout; j++) {
|
||||
/* a read return value of 1 means semaphore acuqire */
|
||||
tmp = RREG32_NO_KIQ(hub->vm_inv_eng0_sem + eng);
|
||||
if (tmp & 0x1)
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (j >= adev->usec_timeout)
|
||||
DRM_ERROR("Timeout waiting for sem acquire in VM flush!\n");
|
||||
}
|
||||
|
||||
WREG32_NO_KIQ(hub->vm_inv_eng0_req + eng, tmp);
|
||||
|
||||
/*
|
||||
@ -506,7 +547,17 @@ static void gmc_v9_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid,
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
|
||||
if (use_semaphore)
|
||||
/*
|
||||
* add semaphore release after invalidation,
|
||||
* write with 0 means semaphore release
|
||||
*/
|
||||
WREG32_NO_KIQ(hub->vm_inv_eng0_sem + eng, 0);
|
||||
|
||||
spin_unlock(&adev->gmc.invalidate_lock);
|
||||
|
||||
if (j < adev->usec_timeout)
|
||||
return;
|
||||
|
||||
@ -516,11 +567,25 @@ static void gmc_v9_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid,
|
||||
static uint64_t gmc_v9_0_emit_flush_gpu_tlb(struct amdgpu_ring *ring,
|
||||
unsigned vmid, uint64_t pd_addr)
|
||||
{
|
||||
bool use_semaphore = gmc_v9_0_use_invalidate_semaphore(ring->adev, ring->funcs->vmhub);
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
struct amdgpu_vmhub *hub = &adev->vmhub[ring->funcs->vmhub];
|
||||
uint32_t req = gmc_v9_0_get_invalidate_req(vmid, 0);
|
||||
unsigned eng = ring->vm_inv_eng;
|
||||
|
||||
/*
|
||||
* It may lose gpuvm invalidate acknowldege state across power-gating
|
||||
* off cycle, add semaphore acquire before invalidation and semaphore
|
||||
* release after invalidation to avoid entering power gated state
|
||||
* to WA the Issue
|
||||
*/
|
||||
|
||||
/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
|
||||
if (use_semaphore)
|
||||
/* a read return value of 1 means semaphore acuqire */
|
||||
amdgpu_ring_emit_reg_wait(ring,
|
||||
hub->vm_inv_eng0_sem + eng, 0x1, 0x1);
|
||||
|
||||
amdgpu_ring_emit_wreg(ring, hub->ctx0_ptb_addr_lo32 + (2 * vmid),
|
||||
lower_32_bits(pd_addr));
|
||||
|
||||
@ -531,6 +596,14 @@ static uint64_t gmc_v9_0_emit_flush_gpu_tlb(struct amdgpu_ring *ring,
|
||||
hub->vm_inv_eng0_ack + eng,
|
||||
req, 1 << vmid);
|
||||
|
||||
/* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */
|
||||
if (use_semaphore)
|
||||
/*
|
||||
* add semaphore release after invalidation,
|
||||
* write with 0 means semaphore release
|
||||
*/
|
||||
amdgpu_ring_emit_wreg(ring, hub->vm_inv_eng0_sem + eng, 0);
|
||||
|
||||
return pd_addr;
|
||||
}
|
||||
|
||||
|
@ -418,6 +418,8 @@ void mmhub_v1_0_init(struct amdgpu_device *adev)
|
||||
hub->ctx0_ptb_addr_hi32 =
|
||||
SOC15_REG_OFFSET(MMHUB, 0,
|
||||
mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32);
|
||||
hub->vm_inv_eng0_sem =
|
||||
SOC15_REG_OFFSET(MMHUB, 0, mmVM_INVALIDATE_ENG0_SEM);
|
||||
hub->vm_inv_eng0_req =
|
||||
SOC15_REG_OFFSET(MMHUB, 0, mmVM_INVALIDATE_ENG0_REQ);
|
||||
hub->vm_inv_eng0_ack =
|
||||
|
@ -341,6 +341,8 @@ void mmhub_v2_0_init(struct amdgpu_device *adev)
|
||||
hub->ctx0_ptb_addr_hi32 =
|
||||
SOC15_REG_OFFSET(MMHUB, 0,
|
||||
mmMMVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32);
|
||||
hub->vm_inv_eng0_sem =
|
||||
SOC15_REG_OFFSET(MMHUB, 0, mmMMVM_INVALIDATE_ENG0_SEM);
|
||||
hub->vm_inv_eng0_req =
|
||||
SOC15_REG_OFFSET(MMHUB, 0, mmMMVM_INVALIDATE_ENG0_REQ);
|
||||
hub->vm_inv_eng0_ack =
|
||||
|
@ -502,6 +502,10 @@ void mmhub_v9_4_init(struct amdgpu_device *adev)
|
||||
SOC15_REG_OFFSET(MMHUB, 0,
|
||||
mmVML2VC0_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32) +
|
||||
i * MMHUB_INSTANCE_REGISTER_OFFSET;
|
||||
hub[i]->vm_inv_eng0_sem =
|
||||
SOC15_REG_OFFSET(MMHUB, 0,
|
||||
mmVML2VC0_VM_INVALIDATE_ENG0_SEM) +
|
||||
i * MMHUB_INSTANCE_REGISTER_OFFSET;
|
||||
hub[i]->vm_inv_eng0_req =
|
||||
SOC15_REG_OFFSET(MMHUB, 0,
|
||||
mmVML2VC0_VM_INVALIDATE_ENG0_REQ) +
|
||||
|
@ -28,8 +28,8 @@
|
||||
#include "nbio_v7_0.h"
|
||||
#include "nbio_v7_4.h"
|
||||
|
||||
#define SOC15_FLUSH_GPU_TLB_NUM_WREG 4
|
||||
#define SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT 1
|
||||
#define SOC15_FLUSH_GPU_TLB_NUM_WREG 6
|
||||
#define SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT 3
|
||||
|
||||
extern const struct amd_ip_funcs soc15_common_ip_funcs;
|
||||
|
||||
|
@ -342,7 +342,8 @@ bool dm_pp_get_clock_levels_by_type(
|
||||
if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->get_clock_by_type) {
|
||||
if (adev->powerplay.pp_funcs->get_clock_by_type(pp_handle,
|
||||
dc_to_pp_clock_type(clk_type), &pp_clks)) {
|
||||
/* Error in pplib. Provide default values. */
|
||||
/* Error in pplib. Provide default values. */
|
||||
get_default_clock_levels(clk_type, dc_clks);
|
||||
return true;
|
||||
}
|
||||
} else if (adev->smu.funcs && adev->smu.funcs->get_clock_by_type) {
|
||||
|
@ -1103,6 +1103,25 @@ void dcn20_pipe_control_lock(
|
||||
if (pipe->plane_state != NULL)
|
||||
flip_immediate = pipe->plane_state->flip_immediate;
|
||||
|
||||
if (flip_immediate && lock) {
|
||||
const int TIMEOUT_FOR_FLIP_PENDING = 100000;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < TIMEOUT_FOR_FLIP_PENDING; ++i) {
|
||||
if (!pipe->plane_res.hubp->funcs->hubp_is_flip_pending(pipe->plane_res.hubp))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (pipe->bottom_pipe != NULL) {
|
||||
for (i = 0; i < TIMEOUT_FOR_FLIP_PENDING; ++i) {
|
||||
if (!pipe->bottom_pipe->plane_res.hubp->funcs->hubp_is_flip_pending(pipe->bottom_pipe->plane_res.hubp))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* In flip immediate and pipe splitting case, we need to use GSL
|
||||
* for synchronization. Only do setup on locking and on flip type change.
|
||||
*/
|
||||
|
@ -2465,9 +2465,11 @@ int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr)
|
||||
drm_dp_mst_topology_put_port(port);
|
||||
}
|
||||
|
||||
for (i = 0; i < mgr->max_payloads; i++) {
|
||||
if (mgr->payloads[i].payload_state != DP_PAYLOAD_DELETE_LOCAL)
|
||||
for (i = 0; i < mgr->max_payloads; /* do nothing */) {
|
||||
if (mgr->payloads[i].payload_state != DP_PAYLOAD_DELETE_LOCAL) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("removing payload %d\n", i);
|
||||
for (j = i; j < mgr->max_payloads - 1; j++) {
|
||||
|
@ -1284,7 +1284,7 @@ static int intel_sanitize_fbc_option(struct drm_i915_private *dev_priv)
|
||||
return 0;
|
||||
|
||||
/* https://bugs.freedesktop.org/show_bug.cgi?id=108085 */
|
||||
if (IS_GEMINILAKE(dev_priv))
|
||||
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
|
||||
return 0;
|
||||
|
||||
if (IS_BROADWELL(dev_priv) || INTEL_GEN(dev_priv) >= 9)
|
||||
|
@ -1597,9 +1597,9 @@ static int cmd_handler_mi_op_2f(struct parser_exec_state *s)
|
||||
if (!(cmd_val(s, 0) & (1 << 22)))
|
||||
return ret;
|
||||
|
||||
/* check if QWORD */
|
||||
if (DWORD_FIELD(0, 20, 19) == 1)
|
||||
valid_len += 8;
|
||||
/* check inline data */
|
||||
if (cmd_val(s, 0) & BIT(18))
|
||||
valid_len = CMD_LEN(9);
|
||||
ret = gvt_check_valid_cmd_length(cmd_length(s),
|
||||
valid_len);
|
||||
if (ret)
|
||||
|
@ -64,6 +64,25 @@ struct meson_cvbs_mode meson_cvbs_modes[MESON_CVBS_MODES_COUNT] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct meson_cvbs_mode *
|
||||
meson_cvbs_get_mode(const struct drm_display_mode *req_mode)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
|
||||
struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
|
||||
|
||||
if (drm_mode_match(req_mode, &meson_mode->mode,
|
||||
DRM_MODE_MATCH_TIMINGS |
|
||||
DRM_MODE_MATCH_CLOCK |
|
||||
DRM_MODE_MATCH_FLAGS |
|
||||
DRM_MODE_MATCH_3D_FLAGS))
|
||||
return meson_mode;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Connector */
|
||||
|
||||
static void meson_cvbs_connector_destroy(struct drm_connector *connector)
|
||||
@ -136,14 +155,8 @@ static int meson_venc_cvbs_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
|
||||
struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
|
||||
|
||||
if (drm_mode_equal(&crtc_state->mode, &meson_mode->mode))
|
||||
return 0;
|
||||
}
|
||||
if (meson_cvbs_get_mode(&crtc_state->mode))
|
||||
return 0;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -191,24 +204,17 @@ static void meson_venc_cvbs_encoder_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
const struct meson_cvbs_mode *meson_mode = meson_cvbs_get_mode(mode);
|
||||
struct meson_venc_cvbs *meson_venc_cvbs =
|
||||
encoder_to_meson_venc_cvbs(encoder);
|
||||
struct meson_drm *priv = meson_venc_cvbs->priv;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
|
||||
struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
|
||||
if (meson_mode) {
|
||||
meson_venci_cvbs_mode_set(priv, meson_mode->enci);
|
||||
|
||||
if (drm_mode_equal(mode, &meson_mode->mode)) {
|
||||
meson_venci_cvbs_mode_set(priv,
|
||||
meson_mode->enci);
|
||||
|
||||
/* Setup 27MHz vclk2 for ENCI and VDAC */
|
||||
meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS,
|
||||
MESON_VCLK_CVBS, MESON_VCLK_CVBS,
|
||||
MESON_VCLK_CVBS, true);
|
||||
break;
|
||||
}
|
||||
/* Setup 27MHz vclk2 for ENCI and VDAC */
|
||||
meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS, MESON_VCLK_CVBS,
|
||||
MESON_VCLK_CVBS, MESON_VCLK_CVBS, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,8 @@ module_param_named(modeset, mgag200_modeset, int, 0400);
|
||||
static struct drm_driver driver;
|
||||
|
||||
static const struct pci_device_id pciidlist[] = {
|
||||
{ PCI_VENDOR_ID_MATROX, 0x522, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_A },
|
||||
{ PCI_VENDOR_ID_MATROX, 0x522, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
G200_SE_A | MGAG200_FLAG_HW_BUG_NO_STARTADD},
|
||||
{ PCI_VENDOR_ID_MATROX, 0x524, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_B },
|
||||
{ PCI_VENDOR_ID_MATROX, 0x530, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_EV },
|
||||
{ PCI_VENDOR_ID_MATROX, 0x532, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_WB },
|
||||
@ -63,6 +64,35 @@ static const struct file_operations mgag200_driver_fops = {
|
||||
DRM_VRAM_MM_FILE_OPERATIONS
|
||||
};
|
||||
|
||||
static bool mgag200_pin_bo_at_0(const struct mga_device *mdev)
|
||||
{
|
||||
return mdev->flags & MGAG200_FLAG_HW_BUG_NO_STARTADD;
|
||||
}
|
||||
|
||||
int mgag200_driver_dumb_create(struct drm_file *file,
|
||||
struct drm_device *dev,
|
||||
struct drm_mode_create_dumb *args)
|
||||
{
|
||||
struct mga_device *mdev = dev->dev_private;
|
||||
unsigned long pg_align;
|
||||
|
||||
if (WARN_ONCE(!dev->vram_mm, "VRAM MM not initialized"))
|
||||
return -EINVAL;
|
||||
|
||||
pg_align = 0ul;
|
||||
|
||||
/*
|
||||
* Aligning scanout buffers to the size of the video ram forces
|
||||
* placement at offset 0. Works around a bug where HW does not
|
||||
* respect 'startadd' field.
|
||||
*/
|
||||
if (mgag200_pin_bo_at_0(mdev))
|
||||
pg_align = PFN_UP(mdev->mc.vram_size);
|
||||
|
||||
return drm_gem_vram_fill_create_dumb(file, dev, &dev->vram_mm->bdev,
|
||||
pg_align, false, args);
|
||||
}
|
||||
|
||||
static struct drm_driver driver = {
|
||||
.driver_features = DRIVER_GEM | DRIVER_MODESET,
|
||||
.load = mgag200_driver_load,
|
||||
@ -74,7 +104,9 @@ static struct drm_driver driver = {
|
||||
.major = DRIVER_MAJOR,
|
||||
.minor = DRIVER_MINOR,
|
||||
.patchlevel = DRIVER_PATCHLEVEL,
|
||||
DRM_GEM_VRAM_DRIVER
|
||||
.dumb_create = mgag200_driver_dumb_create,
|
||||
.dumb_map_offset = drm_gem_vram_driver_dumb_mmap_offset,
|
||||
.gem_prime_mmap = drm_gem_prime_mmap,
|
||||
};
|
||||
|
||||
static struct pci_driver mgag200_pci_driver = {
|
||||
|
@ -159,6 +159,12 @@ enum mga_type {
|
||||
G200_EW3,
|
||||
};
|
||||
|
||||
/* HW does not handle 'startadd' field correct. */
|
||||
#define MGAG200_FLAG_HW_BUG_NO_STARTADD (1ul << 8)
|
||||
|
||||
#define MGAG200_TYPE_MASK (0x000000ff)
|
||||
#define MGAG200_FLAG_MASK (0x00ffff00)
|
||||
|
||||
#define IS_G200_SE(mdev) (mdev->type == G200_SE_A || mdev->type == G200_SE_B)
|
||||
|
||||
struct mga_device {
|
||||
@ -188,6 +194,18 @@ struct mga_device {
|
||||
u32 unique_rev_id;
|
||||
};
|
||||
|
||||
static inline enum mga_type
|
||||
mgag200_type_from_driver_data(kernel_ulong_t driver_data)
|
||||
{
|
||||
return (enum mga_type)(driver_data & MGAG200_TYPE_MASK);
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
mgag200_flags_from_driver_data(kernel_ulong_t driver_data)
|
||||
{
|
||||
return driver_data & MGAG200_FLAG_MASK;
|
||||
}
|
||||
|
||||
/* mgag200_mode.c */
|
||||
int mgag200_modeset_init(struct mga_device *mdev);
|
||||
void mgag200_modeset_fini(struct mga_device *mdev);
|
||||
|
@ -94,7 +94,8 @@ static int mgag200_device_init(struct drm_device *dev,
|
||||
struct mga_device *mdev = dev->dev_private;
|
||||
int ret, option;
|
||||
|
||||
mdev->type = flags;
|
||||
mdev->flags = mgag200_flags_from_driver_data(flags);
|
||||
mdev->type = mgag200_type_from_driver_data(flags);
|
||||
|
||||
/* Hardcode the number of CRTCs to 1 */
|
||||
mdev->num_crtc = 1;
|
||||
|
@ -114,6 +114,7 @@ struct nv50_head_atom {
|
||||
u8 nhsync:1;
|
||||
u8 nvsync:1;
|
||||
u8 depth:4;
|
||||
u8 bpc;
|
||||
} or;
|
||||
|
||||
/* Currently only used for MST */
|
||||
|
@ -353,10 +353,20 @@ nv50_outp_atomic_check(struct drm_encoder *encoder,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct nouveau_connector *nv_connector =
|
||||
nouveau_connector(conn_state->connector);
|
||||
return nv50_outp_atomic_check_view(encoder, crtc_state, conn_state,
|
||||
nv_connector->native_mode);
|
||||
struct drm_connector *connector = conn_state->connector;
|
||||
struct nouveau_connector *nv_connector = nouveau_connector(connector);
|
||||
struct nv50_head_atom *asyh = nv50_head_atom(crtc_state);
|
||||
int ret;
|
||||
|
||||
ret = nv50_outp_atomic_check_view(encoder, crtc_state, conn_state,
|
||||
nv_connector->native_mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (crtc_state->mode_changed || crtc_state->connectors_changed)
|
||||
asyh->or.bpc = connector->display_info.bpc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
@ -770,32 +780,54 @@ nv50_msto_atomic_check(struct drm_encoder *encoder,
|
||||
struct nv50_mstm *mstm = mstc->mstm;
|
||||
struct nv50_head_atom *asyh = nv50_head_atom(crtc_state);
|
||||
int slots;
|
||||
int ret;
|
||||
|
||||
ret = nv50_outp_atomic_check_view(encoder, crtc_state, conn_state,
|
||||
mstc->native);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!crtc_state->mode_changed && !crtc_state->connectors_changed)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* When restoring duplicated states, we need to make sure that the bw
|
||||
* remains the same and avoid recalculating it, as the connector's bpc
|
||||
* may have changed after the state was duplicated
|
||||
*/
|
||||
if (!state->duplicated) {
|
||||
const int clock = crtc_state->adjusted_mode.clock;
|
||||
|
||||
if (crtc_state->mode_changed || crtc_state->connectors_changed) {
|
||||
/*
|
||||
* When restoring duplicated states, we need to make sure that
|
||||
* the bw remains the same and avoid recalculating it, as the
|
||||
* connector's bpc may have changed after the state was
|
||||
* duplicated
|
||||
* XXX: Since we don't use HDR in userspace quite yet, limit
|
||||
* the bpc to 8 to save bandwidth on the topology. In the
|
||||
* future, we'll want to properly fix this by dynamically
|
||||
* selecting the highest possible bpc that would fit in the
|
||||
* topology
|
||||
*/
|
||||
if (!state->duplicated) {
|
||||
const int bpp = connector->display_info.bpc * 3;
|
||||
const int clock = crtc_state->adjusted_mode.clock;
|
||||
|
||||
asyh->dp.pbn = drm_dp_calc_pbn_mode(clock, bpp);
|
||||
}
|
||||
|
||||
slots = drm_dp_atomic_find_vcpi_slots(state, &mstm->mgr,
|
||||
mstc->port,
|
||||
asyh->dp.pbn);
|
||||
if (slots < 0)
|
||||
return slots;
|
||||
|
||||
asyh->dp.tu = slots;
|
||||
asyh->or.bpc = min(connector->display_info.bpc, 8U);
|
||||
asyh->dp.pbn = drm_dp_calc_pbn_mode(clock, asyh->or.bpc * 3);
|
||||
}
|
||||
|
||||
return nv50_outp_atomic_check_view(encoder, crtc_state, conn_state,
|
||||
mstc->native);
|
||||
slots = drm_dp_atomic_find_vcpi_slots(state, &mstm->mgr, mstc->port,
|
||||
asyh->dp.pbn);
|
||||
if (slots < 0)
|
||||
return slots;
|
||||
|
||||
asyh->dp.tu = slots;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8
|
||||
nv50_dp_bpc_to_depth(unsigned int bpc)
|
||||
{
|
||||
switch (bpc) {
|
||||
case 6: return 0x2;
|
||||
case 8: return 0x5;
|
||||
case 10: /* fall-through */
|
||||
default: return 0x6;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -808,7 +840,7 @@ nv50_msto_enable(struct drm_encoder *encoder)
|
||||
struct nv50_mstm *mstm = NULL;
|
||||
struct drm_connector *connector;
|
||||
struct drm_connector_list_iter conn_iter;
|
||||
u8 proto, depth;
|
||||
u8 proto;
|
||||
bool r;
|
||||
|
||||
drm_connector_list_iter_begin(encoder->dev, &conn_iter);
|
||||
@ -837,14 +869,8 @@ nv50_msto_enable(struct drm_encoder *encoder)
|
||||
else
|
||||
proto = 0x9;
|
||||
|
||||
switch (mstc->connector.display_info.bpc) {
|
||||
case 6: depth = 0x2; break;
|
||||
case 8: depth = 0x5; break;
|
||||
case 10:
|
||||
default: depth = 0x6; break;
|
||||
}
|
||||
|
||||
mstm->outp->update(mstm->outp, head->base.index, armh, proto, depth);
|
||||
mstm->outp->update(mstm->outp, head->base.index, armh, proto,
|
||||
nv50_dp_bpc_to_depth(armh->or.bpc));
|
||||
|
||||
msto->head = head;
|
||||
msto->mstc = mstc;
|
||||
@ -1498,20 +1524,14 @@ nv50_sor_enable(struct drm_encoder *encoder)
|
||||
lvds.lvds.script |= 0x0200;
|
||||
}
|
||||
|
||||
if (nv_connector->base.display_info.bpc == 8)
|
||||
if (asyh->or.bpc == 8)
|
||||
lvds.lvds.script |= 0x0200;
|
||||
}
|
||||
|
||||
nvif_mthd(&disp->disp->object, 0, &lvds, sizeof(lvds));
|
||||
break;
|
||||
case DCB_OUTPUT_DP:
|
||||
if (nv_connector->base.display_info.bpc == 6)
|
||||
depth = 0x2;
|
||||
else
|
||||
if (nv_connector->base.display_info.bpc == 8)
|
||||
depth = 0x5;
|
||||
else
|
||||
depth = 0x6;
|
||||
depth = nv50_dp_bpc_to_depth(asyh->or.bpc);
|
||||
|
||||
if (nv_encoder->link & 1)
|
||||
proto = 0x8;
|
||||
@ -1662,7 +1682,7 @@ nv50_pior_enable(struct drm_encoder *encoder)
|
||||
nv50_outp_acquire(nv_encoder);
|
||||
|
||||
nv_connector = nouveau_encoder_connector_get(nv_encoder);
|
||||
switch (nv_connector->base.display_info.bpc) {
|
||||
switch (asyh->or.bpc) {
|
||||
case 10: asyh->or.depth = 0x6; break;
|
||||
case 8: asyh->or.depth = 0x5; break;
|
||||
case 6: asyh->or.depth = 0x2; break;
|
||||
|
@ -81,18 +81,17 @@ nv50_head_atomic_check_dither(struct nv50_head_atom *armh,
|
||||
struct nv50_head_atom *asyh,
|
||||
struct nouveau_conn_atom *asyc)
|
||||
{
|
||||
struct drm_connector *connector = asyc->state.connector;
|
||||
u32 mode = 0x00;
|
||||
|
||||
if (asyc->dither.mode == DITHERING_MODE_AUTO) {
|
||||
if (asyh->base.depth > connector->display_info.bpc * 3)
|
||||
if (asyh->base.depth > asyh->or.bpc * 3)
|
||||
mode = DITHERING_MODE_DYNAMIC2X2;
|
||||
} else {
|
||||
mode = asyc->dither.mode;
|
||||
}
|
||||
|
||||
if (asyc->dither.depth == DITHERING_DEPTH_AUTO) {
|
||||
if (connector->display_info.bpc >= 8)
|
||||
if (asyh->or.bpc >= 8)
|
||||
mode |= DITHERING_DEPTH_8BPC;
|
||||
} else {
|
||||
mode |= asyc->dither.depth;
|
||||
|
@ -303,14 +303,17 @@ static int panfrost_ioctl_mmap_bo(struct drm_device *dev, void *data,
|
||||
}
|
||||
|
||||
/* Don't allow mmapping of heap objects as pages are not pinned. */
|
||||
if (to_panfrost_bo(gem_obj)->is_heap)
|
||||
return -EINVAL;
|
||||
if (to_panfrost_bo(gem_obj)->is_heap) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = drm_gem_create_mmap_offset(gem_obj);
|
||||
if (ret == 0)
|
||||
args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node);
|
||||
drm_gem_object_put_unlocked(gem_obj);
|
||||
|
||||
out:
|
||||
drm_gem_object_put_unlocked(gem_obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -347,20 +350,19 @@ static int panfrost_ioctl_madvise(struct drm_device *dev, void *data,
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
mutex_lock(&pfdev->shrinker_lock);
|
||||
args->retained = drm_gem_shmem_madvise(gem_obj, args->madv);
|
||||
|
||||
if (args->retained) {
|
||||
struct panfrost_gem_object *bo = to_panfrost_bo(gem_obj);
|
||||
|
||||
mutex_lock(&pfdev->shrinker_lock);
|
||||
|
||||
if (args->madv == PANFROST_MADV_DONTNEED)
|
||||
list_add_tail(&bo->base.madv_list, &pfdev->shrinker_list);
|
||||
list_add_tail(&bo->base.madv_list,
|
||||
&pfdev->shrinker_list);
|
||||
else if (args->madv == PANFROST_MADV_WILLNEED)
|
||||
list_del_init(&bo->base.madv_list);
|
||||
|
||||
mutex_unlock(&pfdev->shrinker_lock);
|
||||
}
|
||||
mutex_unlock(&pfdev->shrinker_lock);
|
||||
|
||||
drm_gem_object_put_unlocked(gem_obj);
|
||||
return 0;
|
||||
|
@ -19,6 +19,16 @@ static void panfrost_gem_free_object(struct drm_gem_object *obj)
|
||||
struct panfrost_gem_object *bo = to_panfrost_bo(obj);
|
||||
struct panfrost_device *pfdev = obj->dev->dev_private;
|
||||
|
||||
/*
|
||||
* Make sure the BO is no longer inserted in the shrinker list before
|
||||
* taking care of the destruction itself. If we don't do that we have a
|
||||
* race condition between this function and what's done in
|
||||
* panfrost_gem_shrinker_scan().
|
||||
*/
|
||||
mutex_lock(&pfdev->shrinker_lock);
|
||||
list_del_init(&bo->base.madv_list);
|
||||
mutex_unlock(&pfdev->shrinker_lock);
|
||||
|
||||
if (bo->sgts) {
|
||||
int i;
|
||||
int n_sgt = bo->base.base.size / SZ_2M;
|
||||
@ -33,11 +43,6 @@ static void panfrost_gem_free_object(struct drm_gem_object *obj)
|
||||
kfree(bo->sgts);
|
||||
}
|
||||
|
||||
mutex_lock(&pfdev->shrinker_lock);
|
||||
if (!list_empty(&bo->base.madv_list))
|
||||
list_del(&bo->base.madv_list);
|
||||
mutex_unlock(&pfdev->shrinker_lock);
|
||||
|
||||
drm_gem_shmem_free_object(obj);
|
||||
}
|
||||
|
||||
|
@ -1826,8 +1826,8 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
|
||||
track->textures[i].use_pitch = 1;
|
||||
} else {
|
||||
track->textures[i].use_pitch = 0;
|
||||
track->textures[i].width = 1 << ((idx_value >> RADEON_TXFORMAT_WIDTH_SHIFT) & RADEON_TXFORMAT_WIDTH_MASK);
|
||||
track->textures[i].height = 1 << ((idx_value >> RADEON_TXFORMAT_HEIGHT_SHIFT) & RADEON_TXFORMAT_HEIGHT_MASK);
|
||||
track->textures[i].width = 1 << ((idx_value & RADEON_TXFORMAT_WIDTH_MASK) >> RADEON_TXFORMAT_WIDTH_SHIFT);
|
||||
track->textures[i].height = 1 << ((idx_value & RADEON_TXFORMAT_HEIGHT_MASK) >> RADEON_TXFORMAT_HEIGHT_SHIFT);
|
||||
}
|
||||
if (idx_value & RADEON_TXFORMAT_CUBIC_MAP_ENABLE)
|
||||
track->textures[i].tex_coord_type = 2;
|
||||
|
@ -476,8 +476,8 @@ int r200_packet0_check(struct radeon_cs_parser *p,
|
||||
track->textures[i].use_pitch = 1;
|
||||
} else {
|
||||
track->textures[i].use_pitch = 0;
|
||||
track->textures[i].width = 1 << ((idx_value >> RADEON_TXFORMAT_WIDTH_SHIFT) & RADEON_TXFORMAT_WIDTH_MASK);
|
||||
track->textures[i].height = 1 << ((idx_value >> RADEON_TXFORMAT_HEIGHT_SHIFT) & RADEON_TXFORMAT_HEIGHT_MASK);
|
||||
track->textures[i].width = 1 << ((idx_value & RADEON_TXFORMAT_WIDTH_MASK) >> RADEON_TXFORMAT_WIDTH_SHIFT);
|
||||
track->textures[i].height = 1 << ((idx_value & RADEON_TXFORMAT_HEIGHT_MASK) >> RADEON_TXFORMAT_HEIGHT_SHIFT);
|
||||
}
|
||||
if (idx_value & R200_TXFORMAT_LOOKUP_DISABLE)
|
||||
track->textures[i].lookup_disable = true;
|
||||
|
@ -67,23 +67,34 @@ struct superblock_disk {
|
||||
* To save constantly doing look ups on disk we keep an in core copy of the
|
||||
* on-disk bitmap, the region_map.
|
||||
*
|
||||
* To further reduce metadata I/O overhead we use a second bitmap, the dmap
|
||||
* (dirty bitmap), which tracks the dirty words, i.e. longs, of the region_map.
|
||||
* In order to track which regions are hydrated during a metadata transaction,
|
||||
* we use a second set of bitmaps, the dmap (dirty bitmap), which includes two
|
||||
* bitmaps, namely dirty_regions and dirty_words. The dirty_regions bitmap
|
||||
* tracks the regions that got hydrated during the current metadata
|
||||
* transaction. The dirty_words bitmap tracks the dirty words, i.e. longs, of
|
||||
* the dirty_regions bitmap.
|
||||
*
|
||||
* This allows us to precisely track the regions that were hydrated during the
|
||||
* current metadata transaction and update the metadata accordingly, when we
|
||||
* commit the current transaction. This is important because dm-clone should
|
||||
* only commit the metadata of regions that were properly flushed to the
|
||||
* destination device beforehand. Otherwise, in case of a crash, we could end
|
||||
* up with a corrupted dm-clone device.
|
||||
*
|
||||
* When a region finishes hydrating dm-clone calls
|
||||
* dm_clone_set_region_hydrated(), or for discard requests
|
||||
* dm_clone_cond_set_range(), which sets the corresponding bits in region_map
|
||||
* and dmap.
|
||||
*
|
||||
* During a metadata commit we scan the dmap for dirty region_map words (longs)
|
||||
* and update accordingly the on-disk metadata. Thus, we don't have to flush to
|
||||
* disk the whole region_map. We can just flush the dirty region_map words.
|
||||
* During a metadata commit we scan dmap->dirty_words and dmap->dirty_regions
|
||||
* and update the on-disk metadata accordingly. Thus, we don't have to flush to
|
||||
* disk the whole region_map. We can just flush the dirty region_map bits.
|
||||
*
|
||||
* We use a dirty bitmap, which is smaller than the original region_map, to
|
||||
* reduce the amount of memory accesses during a metadata commit. As dm-bitset
|
||||
* accesses the on-disk bitmap in 64-bit word granularity, there is no
|
||||
* significant benefit in tracking the dirty region_map bits with a smaller
|
||||
* granularity.
|
||||
* We use the helper dmap->dirty_words bitmap, which is smaller than the
|
||||
* original region_map, to reduce the amount of memory accesses during a
|
||||
* metadata commit. Moreover, as dm-bitset also accesses the on-disk bitmap in
|
||||
* 64-bit word granularity, the dirty_words bitmap helps us avoid useless disk
|
||||
* accesses.
|
||||
*
|
||||
* We could update directly the on-disk bitmap, when dm-clone calls either
|
||||
* dm_clone_set_region_hydrated() or dm_clone_cond_set_range(), buts this
|
||||
@ -92,12 +103,13 @@ struct superblock_disk {
|
||||
* e.g., in a hooked overwrite bio's completion routine, and further reduce the
|
||||
* I/O completion latency.
|
||||
*
|
||||
* We maintain two dirty bitmaps. During a metadata commit we atomically swap
|
||||
* the currently used dmap with the unused one. This allows the metadata update
|
||||
* functions to run concurrently with an ongoing commit.
|
||||
* We maintain two dirty bitmap sets. During a metadata commit we atomically
|
||||
* swap the currently used dmap with the unused one. This allows the metadata
|
||||
* update functions to run concurrently with an ongoing commit.
|
||||
*/
|
||||
struct dirty_map {
|
||||
unsigned long *dirty_words;
|
||||
unsigned long *dirty_regions;
|
||||
unsigned int changed;
|
||||
};
|
||||
|
||||
@ -115,6 +127,9 @@ struct dm_clone_metadata {
|
||||
struct dirty_map dmap[2];
|
||||
struct dirty_map *current_dmap;
|
||||
|
||||
/* Protected by lock */
|
||||
struct dirty_map *committing_dmap;
|
||||
|
||||
/*
|
||||
* In core copy of the on-disk bitmap to save constantly doing look ups
|
||||
* on disk.
|
||||
@ -461,34 +476,53 @@ static size_t bitmap_size(unsigned long nr_bits)
|
||||
return BITS_TO_LONGS(nr_bits) * sizeof(long);
|
||||
}
|
||||
|
||||
static int __dirty_map_init(struct dirty_map *dmap, unsigned long nr_words,
|
||||
unsigned long nr_regions)
|
||||
{
|
||||
dmap->changed = 0;
|
||||
|
||||
dmap->dirty_words = kvzalloc(bitmap_size(nr_words), GFP_KERNEL);
|
||||
if (!dmap->dirty_words)
|
||||
return -ENOMEM;
|
||||
|
||||
dmap->dirty_regions = kvzalloc(bitmap_size(nr_regions), GFP_KERNEL);
|
||||
if (!dmap->dirty_regions) {
|
||||
kvfree(dmap->dirty_words);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __dirty_map_exit(struct dirty_map *dmap)
|
||||
{
|
||||
kvfree(dmap->dirty_words);
|
||||
kvfree(dmap->dirty_regions);
|
||||
}
|
||||
|
||||
static int dirty_map_init(struct dm_clone_metadata *cmd)
|
||||
{
|
||||
cmd->dmap[0].changed = 0;
|
||||
cmd->dmap[0].dirty_words = kvzalloc(bitmap_size(cmd->nr_words), GFP_KERNEL);
|
||||
|
||||
if (!cmd->dmap[0].dirty_words) {
|
||||
if (__dirty_map_init(&cmd->dmap[0], cmd->nr_words, cmd->nr_regions)) {
|
||||
DMERR("Failed to allocate dirty bitmap");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cmd->dmap[1].changed = 0;
|
||||
cmd->dmap[1].dirty_words = kvzalloc(bitmap_size(cmd->nr_words), GFP_KERNEL);
|
||||
|
||||
if (!cmd->dmap[1].dirty_words) {
|
||||
if (__dirty_map_init(&cmd->dmap[1], cmd->nr_words, cmd->nr_regions)) {
|
||||
DMERR("Failed to allocate dirty bitmap");
|
||||
kvfree(cmd->dmap[0].dirty_words);
|
||||
__dirty_map_exit(&cmd->dmap[0]);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cmd->current_dmap = &cmd->dmap[0];
|
||||
cmd->committing_dmap = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dirty_map_exit(struct dm_clone_metadata *cmd)
|
||||
{
|
||||
kvfree(cmd->dmap[0].dirty_words);
|
||||
kvfree(cmd->dmap[1].dirty_words);
|
||||
__dirty_map_exit(&cmd->dmap[0]);
|
||||
__dirty_map_exit(&cmd->dmap[1]);
|
||||
}
|
||||
|
||||
static int __load_bitset_in_core(struct dm_clone_metadata *cmd)
|
||||
@ -633,21 +667,23 @@ unsigned long dm_clone_find_next_unhydrated_region(struct dm_clone_metadata *cmd
|
||||
return find_next_zero_bit(cmd->region_map, cmd->nr_regions, start);
|
||||
}
|
||||
|
||||
static int __update_metadata_word(struct dm_clone_metadata *cmd, unsigned long word)
|
||||
static int __update_metadata_word(struct dm_clone_metadata *cmd,
|
||||
unsigned long *dirty_regions,
|
||||
unsigned long word)
|
||||
{
|
||||
int r;
|
||||
unsigned long index = word * BITS_PER_LONG;
|
||||
unsigned long max_index = min(cmd->nr_regions, (word + 1) * BITS_PER_LONG);
|
||||
|
||||
while (index < max_index) {
|
||||
if (test_bit(index, cmd->region_map)) {
|
||||
if (test_bit(index, dirty_regions)) {
|
||||
r = dm_bitset_set_bit(&cmd->bitset_info, cmd->bitset_root,
|
||||
index, &cmd->bitset_root);
|
||||
|
||||
if (r) {
|
||||
DMERR("dm_bitset_set_bit failed");
|
||||
return r;
|
||||
}
|
||||
__clear_bit(index, dirty_regions);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
@ -721,7 +757,7 @@ static int __flush_dmap(struct dm_clone_metadata *cmd, struct dirty_map *dmap)
|
||||
if (word == cmd->nr_words)
|
||||
break;
|
||||
|
||||
r = __update_metadata_word(cmd, word);
|
||||
r = __update_metadata_word(cmd, dmap->dirty_regions, word);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
@ -743,16 +779,18 @@ static int __flush_dmap(struct dm_clone_metadata *cmd, struct dirty_map *dmap)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dm_clone_metadata_commit(struct dm_clone_metadata *cmd)
|
||||
int dm_clone_metadata_pre_commit(struct dm_clone_metadata *cmd)
|
||||
{
|
||||
int r = -EPERM;
|
||||
int r = 0;
|
||||
unsigned long flags;
|
||||
struct dirty_map *dmap, *next_dmap;
|
||||
|
||||
down_write(&cmd->lock);
|
||||
|
||||
if (cmd->fail_io || dm_bm_is_read_only(cmd->bm))
|
||||
if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) {
|
||||
r = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Get current dirty bitmap */
|
||||
dmap = cmd->current_dmap;
|
||||
@ -764,7 +802,7 @@ int dm_clone_metadata_commit(struct dm_clone_metadata *cmd)
|
||||
* The last commit failed, so we don't have a clean dirty-bitmap to
|
||||
* use.
|
||||
*/
|
||||
if (WARN_ON(next_dmap->changed)) {
|
||||
if (WARN_ON(next_dmap->changed || cmd->committing_dmap)) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@ -774,11 +812,33 @@ int dm_clone_metadata_commit(struct dm_clone_metadata *cmd)
|
||||
cmd->current_dmap = next_dmap;
|
||||
spin_unlock_irqrestore(&cmd->bitmap_lock, flags);
|
||||
|
||||
/*
|
||||
* No one is accessing the old dirty bitmap anymore, so we can flush
|
||||
* it.
|
||||
*/
|
||||
r = __flush_dmap(cmd, dmap);
|
||||
/* Set old dirty bitmap as currently committing */
|
||||
cmd->committing_dmap = dmap;
|
||||
out:
|
||||
up_write(&cmd->lock);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int dm_clone_metadata_commit(struct dm_clone_metadata *cmd)
|
||||
{
|
||||
int r = -EPERM;
|
||||
|
||||
down_write(&cmd->lock);
|
||||
|
||||
if (cmd->fail_io || dm_bm_is_read_only(cmd->bm))
|
||||
goto out;
|
||||
|
||||
if (WARN_ON(!cmd->committing_dmap)) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = __flush_dmap(cmd, cmd->committing_dmap);
|
||||
if (!r) {
|
||||
/* Clear committing dmap */
|
||||
cmd->committing_dmap = NULL;
|
||||
}
|
||||
out:
|
||||
up_write(&cmd->lock);
|
||||
|
||||
@ -803,6 +863,7 @@ int dm_clone_set_region_hydrated(struct dm_clone_metadata *cmd, unsigned long re
|
||||
dmap = cmd->current_dmap;
|
||||
|
||||
__set_bit(word, dmap->dirty_words);
|
||||
__set_bit(region_nr, dmap->dirty_regions);
|
||||
__set_bit(region_nr, cmd->region_map);
|
||||
dmap->changed = 1;
|
||||
|
||||
@ -831,6 +892,7 @@ int dm_clone_cond_set_range(struct dm_clone_metadata *cmd, unsigned long start,
|
||||
if (!test_bit(region_nr, cmd->region_map)) {
|
||||
word = region_nr / BITS_PER_LONG;
|
||||
__set_bit(word, dmap->dirty_words);
|
||||
__set_bit(region_nr, dmap->dirty_regions);
|
||||
__set_bit(region_nr, cmd->region_map);
|
||||
dmap->changed = 1;
|
||||
}
|
||||
|
@ -73,7 +73,23 @@ void dm_clone_metadata_close(struct dm_clone_metadata *cmd);
|
||||
|
||||
/*
|
||||
* Commit dm-clone metadata to disk.
|
||||
*
|
||||
* We use a two phase commit:
|
||||
*
|
||||
* 1. dm_clone_metadata_pre_commit(): Prepare the current transaction for
|
||||
* committing. After this is called, all subsequent metadata updates, done
|
||||
* through either dm_clone_set_region_hydrated() or
|
||||
* dm_clone_cond_set_range(), will be part of the **next** transaction.
|
||||
*
|
||||
* 2. dm_clone_metadata_commit(): Actually commit the current transaction to
|
||||
* disk and start a new transaction.
|
||||
*
|
||||
* This allows dm-clone to flush the destination device after step (1) to
|
||||
* ensure that all freshly hydrated regions, for which we are updating the
|
||||
* metadata, are properly written to non-volatile storage and won't be lost in
|
||||
* case of a crash.
|
||||
*/
|
||||
int dm_clone_metadata_pre_commit(struct dm_clone_metadata *cmd);
|
||||
int dm_clone_metadata_commit(struct dm_clone_metadata *cmd);
|
||||
|
||||
/*
|
||||
@ -110,6 +126,7 @@ int dm_clone_metadata_abort(struct dm_clone_metadata *cmd);
|
||||
* Switches metadata to a read only mode. Once read-only mode has been entered
|
||||
* the following functions will return -EPERM:
|
||||
*
|
||||
* dm_clone_metadata_pre_commit()
|
||||
* dm_clone_metadata_commit()
|
||||
* dm_clone_set_region_hydrated()
|
||||
* dm_clone_cond_set_range()
|
||||
|
@ -86,6 +86,12 @@ struct clone {
|
||||
|
||||
struct dm_clone_metadata *cmd;
|
||||
|
||||
/*
|
||||
* bio used to flush the destination device, before committing the
|
||||
* metadata.
|
||||
*/
|
||||
struct bio flush_bio;
|
||||
|
||||
/* Region hydration hash table */
|
||||
struct hash_table_bucket *ht;
|
||||
|
||||
@ -1106,10 +1112,13 @@ static bool need_commit_due_to_time(struct clone *clone)
|
||||
/*
|
||||
* A non-zero return indicates read-only or fail mode.
|
||||
*/
|
||||
static int commit_metadata(struct clone *clone)
|
||||
static int commit_metadata(struct clone *clone, bool *dest_dev_flushed)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
if (dest_dev_flushed)
|
||||
*dest_dev_flushed = false;
|
||||
|
||||
mutex_lock(&clone->commit_lock);
|
||||
|
||||
if (!dm_clone_changed_this_transaction(clone->cmd))
|
||||
@ -1120,8 +1129,26 @@ static int commit_metadata(struct clone *clone)
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = dm_clone_metadata_commit(clone->cmd);
|
||||
r = dm_clone_metadata_pre_commit(clone->cmd);
|
||||
if (unlikely(r)) {
|
||||
__metadata_operation_failed(clone, "dm_clone_metadata_pre_commit", r);
|
||||
goto out;
|
||||
}
|
||||
|
||||
bio_reset(&clone->flush_bio);
|
||||
bio_set_dev(&clone->flush_bio, clone->dest_dev->bdev);
|
||||
clone->flush_bio.bi_opf = REQ_OP_WRITE | REQ_PREFLUSH;
|
||||
|
||||
r = submit_bio_wait(&clone->flush_bio);
|
||||
if (unlikely(r)) {
|
||||
__metadata_operation_failed(clone, "flush destination device", r);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dest_dev_flushed)
|
||||
*dest_dev_flushed = true;
|
||||
|
||||
r = dm_clone_metadata_commit(clone->cmd);
|
||||
if (unlikely(r)) {
|
||||
__metadata_operation_failed(clone, "dm_clone_metadata_commit", r);
|
||||
goto out;
|
||||
@ -1194,6 +1221,7 @@ static void process_deferred_flush_bios(struct clone *clone)
|
||||
{
|
||||
struct bio *bio;
|
||||
unsigned long flags;
|
||||
bool dest_dev_flushed;
|
||||
struct bio_list bios = BIO_EMPTY_LIST;
|
||||
struct bio_list bio_completions = BIO_EMPTY_LIST;
|
||||
|
||||
@ -1213,7 +1241,7 @@ static void process_deferred_flush_bios(struct clone *clone)
|
||||
!(dm_clone_changed_this_transaction(clone->cmd) && need_commit_due_to_time(clone)))
|
||||
return;
|
||||
|
||||
if (commit_metadata(clone)) {
|
||||
if (commit_metadata(clone, &dest_dev_flushed)) {
|
||||
bio_list_merge(&bios, &bio_completions);
|
||||
|
||||
while ((bio = bio_list_pop(&bios)))
|
||||
@ -1227,8 +1255,17 @@ static void process_deferred_flush_bios(struct clone *clone)
|
||||
while ((bio = bio_list_pop(&bio_completions)))
|
||||
bio_endio(bio);
|
||||
|
||||
while ((bio = bio_list_pop(&bios)))
|
||||
generic_make_request(bio);
|
||||
while ((bio = bio_list_pop(&bios))) {
|
||||
if ((bio->bi_opf & REQ_PREFLUSH) && dest_dev_flushed) {
|
||||
/* We just flushed the destination device as part of
|
||||
* the metadata commit, so there is no reason to send
|
||||
* another flush.
|
||||
*/
|
||||
bio_endio(bio);
|
||||
} else {
|
||||
generic_make_request(bio);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void do_worker(struct work_struct *work)
|
||||
@ -1400,7 +1437,7 @@ static void clone_status(struct dm_target *ti, status_type_t type,
|
||||
|
||||
/* Commit to ensure statistics aren't out-of-date */
|
||||
if (!(status_flags & DM_STATUS_NOFLUSH_FLAG) && !dm_suspended(ti))
|
||||
(void) commit_metadata(clone);
|
||||
(void) commit_metadata(clone, NULL);
|
||||
|
||||
r = dm_clone_get_free_metadata_block_count(clone->cmd, &nr_free_metadata_blocks);
|
||||
|
||||
@ -1834,6 +1871,7 @@ static int clone_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
bio_list_init(&clone->deferred_flush_completions);
|
||||
clone->hydration_offset = 0;
|
||||
atomic_set(&clone->hydrations_in_flight, 0);
|
||||
bio_init(&clone->flush_bio, NULL, 0);
|
||||
|
||||
clone->wq = alloc_workqueue("dm-" DM_MSG_PREFIX, WQ_MEM_RECLAIM, 0);
|
||||
if (!clone->wq) {
|
||||
@ -1907,6 +1945,7 @@ static void clone_dtr(struct dm_target *ti)
|
||||
struct clone *clone = ti->private;
|
||||
|
||||
mutex_destroy(&clone->commit_lock);
|
||||
bio_uninit(&clone->flush_bio);
|
||||
|
||||
for (i = 0; i < clone->nr_ctr_args; i++)
|
||||
kfree(clone->ctr_args[i]);
|
||||
@ -1961,7 +2000,7 @@ static void clone_postsuspend(struct dm_target *ti)
|
||||
wait_event(clone->hydration_stopped, !atomic_read(&clone->hydrations_in_flight));
|
||||
flush_workqueue(clone->wq);
|
||||
|
||||
(void) commit_metadata(clone);
|
||||
(void) commit_metadata(clone, NULL);
|
||||
}
|
||||
|
||||
static void clone_resume(struct dm_target *ti)
|
||||
|
@ -599,45 +599,10 @@ static struct pgpath *__map_bio(struct multipath *m, struct bio *bio)
|
||||
return pgpath;
|
||||
}
|
||||
|
||||
static struct pgpath *__map_bio_fast(struct multipath *m, struct bio *bio)
|
||||
{
|
||||
struct pgpath *pgpath;
|
||||
unsigned long flags;
|
||||
|
||||
/* Do we need to select a new pgpath? */
|
||||
/*
|
||||
* FIXME: currently only switching path if no path (due to failure, etc)
|
||||
* - which negates the point of using a path selector
|
||||
*/
|
||||
pgpath = READ_ONCE(m->current_pgpath);
|
||||
if (!pgpath)
|
||||
pgpath = choose_pgpath(m, bio->bi_iter.bi_size);
|
||||
|
||||
if (!pgpath) {
|
||||
if (test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)) {
|
||||
/* Queue for the daemon to resubmit */
|
||||
spin_lock_irqsave(&m->lock, flags);
|
||||
bio_list_add(&m->queued_bios, bio);
|
||||
spin_unlock_irqrestore(&m->lock, flags);
|
||||
queue_work(kmultipathd, &m->process_queued_bios);
|
||||
|
||||
return ERR_PTR(-EAGAIN);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pgpath;
|
||||
}
|
||||
|
||||
static int __multipath_map_bio(struct multipath *m, struct bio *bio,
|
||||
struct dm_mpath_io *mpio)
|
||||
{
|
||||
struct pgpath *pgpath;
|
||||
|
||||
if (!m->hw_handler_name)
|
||||
pgpath = __map_bio_fast(m, bio);
|
||||
else
|
||||
pgpath = __map_bio(m, bio);
|
||||
struct pgpath *pgpath = __map_bio(m, bio);
|
||||
|
||||
if (IS_ERR(pgpath))
|
||||
return DM_MAPIO_SUBMITTED;
|
||||
|
@ -188,6 +188,15 @@ struct dm_pool_metadata {
|
||||
unsigned long flags;
|
||||
sector_t data_block_size;
|
||||
|
||||
/*
|
||||
* Pre-commit callback.
|
||||
*
|
||||
* This allows the thin provisioning target to run a callback before
|
||||
* the metadata are committed.
|
||||
*/
|
||||
dm_pool_pre_commit_fn pre_commit_fn;
|
||||
void *pre_commit_context;
|
||||
|
||||
/*
|
||||
* We reserve a section of the metadata for commit overhead.
|
||||
* All reported space does *not* include this.
|
||||
@ -826,6 +835,14 @@ static int __commit_transaction(struct dm_pool_metadata *pmd)
|
||||
if (unlikely(!pmd->in_service))
|
||||
return 0;
|
||||
|
||||
if (pmd->pre_commit_fn) {
|
||||
r = pmd->pre_commit_fn(pmd->pre_commit_context);
|
||||
if (r < 0) {
|
||||
DMERR("pre-commit callback failed");
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
r = __write_changed_details(pmd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -892,6 +909,8 @@ struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev,
|
||||
pmd->in_service = false;
|
||||
pmd->bdev = bdev;
|
||||
pmd->data_block_size = data_block_size;
|
||||
pmd->pre_commit_fn = NULL;
|
||||
pmd->pre_commit_context = NULL;
|
||||
|
||||
r = __create_persistent_data_objects(pmd, format_device);
|
||||
if (r) {
|
||||
@ -2044,6 +2063,16 @@ int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd,
|
||||
return r;
|
||||
}
|
||||
|
||||
void dm_pool_register_pre_commit_callback(struct dm_pool_metadata *pmd,
|
||||
dm_pool_pre_commit_fn fn,
|
||||
void *context)
|
||||
{
|
||||
pmd_write_lock_in_core(pmd);
|
||||
pmd->pre_commit_fn = fn;
|
||||
pmd->pre_commit_context = context;
|
||||
pmd_write_unlock(pmd);
|
||||
}
|
||||
|
||||
int dm_pool_metadata_set_needs_check(struct dm_pool_metadata *pmd)
|
||||
{
|
||||
int r = -EINVAL;
|
||||
|
@ -230,6 +230,13 @@ bool dm_pool_metadata_needs_check(struct dm_pool_metadata *pmd);
|
||||
*/
|
||||
void dm_pool_issue_prefetches(struct dm_pool_metadata *pmd);
|
||||
|
||||
/* Pre-commit callback */
|
||||
typedef int (*dm_pool_pre_commit_fn)(void *context);
|
||||
|
||||
void dm_pool_register_pre_commit_callback(struct dm_pool_metadata *pmd,
|
||||
dm_pool_pre_commit_fn fn,
|
||||
void *context);
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
#endif
|
||||
|
@ -328,6 +328,7 @@ struct pool_c {
|
||||
dm_block_t low_water_blocks;
|
||||
struct pool_features requested_pf; /* Features requested during table load */
|
||||
struct pool_features adjusted_pf; /* Features used after adjusting for constituent devices */
|
||||
struct bio flush_bio;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -2392,8 +2393,16 @@ static void process_deferred_bios(struct pool *pool)
|
||||
while ((bio = bio_list_pop(&bio_completions)))
|
||||
bio_endio(bio);
|
||||
|
||||
while ((bio = bio_list_pop(&bios)))
|
||||
generic_make_request(bio);
|
||||
while ((bio = bio_list_pop(&bios))) {
|
||||
/*
|
||||
* The data device was flushed as part of metadata commit,
|
||||
* so complete redundant flushes immediately.
|
||||
*/
|
||||
if (bio->bi_opf & REQ_PREFLUSH)
|
||||
bio_endio(bio);
|
||||
else
|
||||
generic_make_request(bio);
|
||||
}
|
||||
}
|
||||
|
||||
static void do_worker(struct work_struct *ws)
|
||||
@ -3127,6 +3136,7 @@ static void pool_dtr(struct dm_target *ti)
|
||||
__pool_dec(pt->pool);
|
||||
dm_put_device(ti, pt->metadata_dev);
|
||||
dm_put_device(ti, pt->data_dev);
|
||||
bio_uninit(&pt->flush_bio);
|
||||
kfree(pt);
|
||||
|
||||
mutex_unlock(&dm_thin_pool_table.mutex);
|
||||
@ -3192,6 +3202,29 @@ static void metadata_low_callback(void *context)
|
||||
dm_table_event(pool->ti->table);
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to flush the data device **before** committing the metadata.
|
||||
*
|
||||
* This ensures that the data blocks of any newly inserted mappings are
|
||||
* properly written to non-volatile storage and won't be lost in case of a
|
||||
* crash.
|
||||
*
|
||||
* Failure to do so can result in data corruption in the case of internal or
|
||||
* external snapshots and in the case of newly provisioned blocks, when block
|
||||
* zeroing is enabled.
|
||||
*/
|
||||
static int metadata_pre_commit_callback(void *context)
|
||||
{
|
||||
struct pool_c *pt = context;
|
||||
struct bio *flush_bio = &pt->flush_bio;
|
||||
|
||||
bio_reset(flush_bio);
|
||||
bio_set_dev(flush_bio, pt->data_dev->bdev);
|
||||
flush_bio->bi_opf = REQ_OP_WRITE | REQ_PREFLUSH;
|
||||
|
||||
return submit_bio_wait(flush_bio);
|
||||
}
|
||||
|
||||
static sector_t get_dev_size(struct block_device *bdev)
|
||||
{
|
||||
return i_size_read(bdev->bd_inode) >> SECTOR_SHIFT;
|
||||
@ -3360,6 +3393,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
|
||||
pt->data_dev = data_dev;
|
||||
pt->low_water_blocks = low_water_blocks;
|
||||
pt->adjusted_pf = pt->requested_pf = pf;
|
||||
bio_init(&pt->flush_bio, NULL, 0);
|
||||
ti->num_flush_bios = 1;
|
||||
|
||||
/*
|
||||
@ -3386,6 +3420,10 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
|
||||
if (r)
|
||||
goto out_flags_changed;
|
||||
|
||||
dm_pool_register_pre_commit_callback(pt->pool->pmd,
|
||||
metadata_pre_commit_callback,
|
||||
pt);
|
||||
|
||||
pt->callbacks.congested_fn = pool_is_congested;
|
||||
dm_table_add_target_callbacks(ti->table, &pt->callbacks);
|
||||
|
||||
|
@ -203,7 +203,13 @@ static void __rebalance2(struct dm_btree_info *info, struct btree_node *parent,
|
||||
struct btree_node *right = r->n;
|
||||
uint32_t nr_left = le32_to_cpu(left->header.nr_entries);
|
||||
uint32_t nr_right = le32_to_cpu(right->header.nr_entries);
|
||||
unsigned threshold = 2 * merge_threshold(left) + 1;
|
||||
/*
|
||||
* Ensure the number of entries in each child will be greater
|
||||
* than or equal to (max_entries / 3 + 1), so no matter which
|
||||
* child is used for removal, the number will still be not
|
||||
* less than (max_entries / 3).
|
||||
*/
|
||||
unsigned int threshold = 2 * (merge_threshold(left) + 1);
|
||||
|
||||
if (nr_left + nr_right < threshold) {
|
||||
/*
|
||||
|
@ -408,38 +408,6 @@ static int mmc_blk_ioctl_copy_to_user(struct mmc_ioc_cmd __user *ic_ptr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status,
|
||||
u32 retries_max)
|
||||
{
|
||||
int err;
|
||||
u32 retry_count = 0;
|
||||
|
||||
if (!status || !retries_max)
|
||||
return -EINVAL;
|
||||
|
||||
do {
|
||||
err = __mmc_send_status(card, status, 5);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
if (!R1_STATUS(*status) &&
|
||||
(R1_CURRENT_STATE(*status) != R1_STATE_PRG))
|
||||
break; /* RPMB programming operation complete */
|
||||
|
||||
/*
|
||||
* Rechedule to give the MMC device a chance to continue
|
||||
* processing the previous command without being polled too
|
||||
* frequently.
|
||||
*/
|
||||
usleep_range(1000, 5000);
|
||||
} while (++retry_count < retries_max);
|
||||
|
||||
if (retry_count == retries_max)
|
||||
err = -EPERM;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ioctl_do_sanitize(struct mmc_card *card)
|
||||
{
|
||||
int err;
|
||||
@ -468,6 +436,58 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline bool mmc_blk_in_tran_state(u32 status)
|
||||
{
|
||||
/*
|
||||
* Some cards mishandle the status bits, so make sure to check both the
|
||||
* busy indication and the card state.
|
||||
*/
|
||||
return status & R1_READY_FOR_DATA &&
|
||||
(R1_CURRENT_STATE(status) == R1_STATE_TRAN);
|
||||
}
|
||||
|
||||
static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms,
|
||||
u32 *resp_errs)
|
||||
{
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
|
||||
int err = 0;
|
||||
u32 status;
|
||||
|
||||
do {
|
||||
bool done = time_after(jiffies, timeout);
|
||||
|
||||
err = __mmc_send_status(card, &status, 5);
|
||||
if (err) {
|
||||
dev_err(mmc_dev(card->host),
|
||||
"error %d requesting status\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Accumulate any response error bits seen */
|
||||
if (resp_errs)
|
||||
*resp_errs |= status;
|
||||
|
||||
/*
|
||||
* Timeout if the device never becomes ready for data and never
|
||||
* leaves the program state.
|
||||
*/
|
||||
if (done) {
|
||||
dev_err(mmc_dev(card->host),
|
||||
"Card stuck in wrong state! %s status: %#x\n",
|
||||
__func__, status);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some cards mishandle the status bits,
|
||||
* so make sure to check both the busy
|
||||
* indication and the card state.
|
||||
*/
|
||||
} while (!mmc_blk_in_tran_state(status));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
|
||||
struct mmc_blk_ioc_data *idata)
|
||||
{
|
||||
@ -477,7 +497,6 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
|
||||
struct scatterlist sg;
|
||||
int err;
|
||||
unsigned int target_part;
|
||||
u32 status = 0;
|
||||
|
||||
if (!card || !md || !idata)
|
||||
return -EINVAL;
|
||||
@ -611,16 +630,12 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
|
||||
|
||||
memcpy(&(idata->ic.response), cmd.resp, sizeof(cmd.resp));
|
||||
|
||||
if (idata->rpmb) {
|
||||
if (idata->rpmb || (cmd.flags & MMC_RSP_R1B)) {
|
||||
/*
|
||||
* Ensure RPMB command has completed by polling CMD13
|
||||
* Ensure RPMB/R1B command has completed by polling CMD13
|
||||
* "Send Status".
|
||||
*/
|
||||
err = ioctl_rpmb_card_status_poll(card, &status, 5);
|
||||
if (err)
|
||||
dev_err(mmc_dev(card->host),
|
||||
"%s: Card Status=0x%08X, error %d\n",
|
||||
__func__, status, err);
|
||||
err = card_busy_detect(card, MMC_BLK_TIMEOUT_MS, NULL);
|
||||
}
|
||||
|
||||
return err;
|
||||
@ -970,58 +985,6 @@ static unsigned int mmc_blk_data_timeout_ms(struct mmc_host *host,
|
||||
return ms;
|
||||
}
|
||||
|
||||
static inline bool mmc_blk_in_tran_state(u32 status)
|
||||
{
|
||||
/*
|
||||
* Some cards mishandle the status bits, so make sure to check both the
|
||||
* busy indication and the card state.
|
||||
*/
|
||||
return status & R1_READY_FOR_DATA &&
|
||||
(R1_CURRENT_STATE(status) == R1_STATE_TRAN);
|
||||
}
|
||||
|
||||
static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms,
|
||||
struct request *req, u32 *resp_errs)
|
||||
{
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
|
||||
int err = 0;
|
||||
u32 status;
|
||||
|
||||
do {
|
||||
bool done = time_after(jiffies, timeout);
|
||||
|
||||
err = __mmc_send_status(card, &status, 5);
|
||||
if (err) {
|
||||
pr_err("%s: error %d requesting status\n",
|
||||
req->rq_disk->disk_name, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Accumulate any response error bits seen */
|
||||
if (resp_errs)
|
||||
*resp_errs |= status;
|
||||
|
||||
/*
|
||||
* Timeout if the device never becomes ready for data and never
|
||||
* leaves the program state.
|
||||
*/
|
||||
if (done) {
|
||||
pr_err("%s: Card stuck in wrong state! %s %s status: %#x\n",
|
||||
mmc_hostname(card->host),
|
||||
req->rq_disk->disk_name, __func__, status);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some cards mishandle the status bits,
|
||||
* so make sure to check both the busy
|
||||
* indication and the card state.
|
||||
*/
|
||||
} while (!mmc_blk_in_tran_state(status));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host,
|
||||
int type)
|
||||
{
|
||||
@ -1671,7 +1634,7 @@ static int mmc_blk_fix_state(struct mmc_card *card, struct request *req)
|
||||
|
||||
mmc_blk_send_stop(card, timeout);
|
||||
|
||||
err = card_busy_detect(card, timeout, req, NULL);
|
||||
err = card_busy_detect(card, timeout, NULL);
|
||||
|
||||
mmc_retune_release(card->host);
|
||||
|
||||
@ -1895,7 +1858,7 @@ static int mmc_blk_card_busy(struct mmc_card *card, struct request *req)
|
||||
if (mmc_host_is_spi(card->host) || rq_data_dir(req) == READ)
|
||||
return 0;
|
||||
|
||||
err = card_busy_detect(card, MMC_BLK_TIMEOUT_MS, req, &status);
|
||||
err = card_busy_detect(card, MMC_BLK_TIMEOUT_MS, &status);
|
||||
|
||||
/*
|
||||
* Do not assume data transferred correctly if there are any error bits
|
||||
|
@ -1469,8 +1469,7 @@ void mmc_detach_bus(struct mmc_host *host)
|
||||
mmc_bus_put(host);
|
||||
}
|
||||
|
||||
static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
|
||||
bool cd_irq)
|
||||
void _mmc_detect_change(struct mmc_host *host, unsigned long delay, bool cd_irq)
|
||||
{
|
||||
/*
|
||||
* If the device is configured as wakeup, we prevent a new sleep for
|
||||
@ -2129,7 +2128,7 @@ int mmc_hw_reset(struct mmc_host *host)
|
||||
ret = host->bus_ops->hw_reset(host);
|
||||
mmc_bus_put(host);
|
||||
|
||||
if (ret)
|
||||
if (ret < 0)
|
||||
pr_warn("%s: tried to HW reset card, got error %d\n",
|
||||
mmc_hostname(host), ret);
|
||||
|
||||
@ -2297,11 +2296,8 @@ void mmc_rescan(struct work_struct *work)
|
||||
|
||||
mmc_bus_get(host);
|
||||
|
||||
/*
|
||||
* if there is a _removable_ card registered, check whether it is
|
||||
* still present
|
||||
*/
|
||||
if (host->bus_ops && !host->bus_dead && mmc_card_is_removable(host))
|
||||
/* Verify a registered card to be functional, else remove it. */
|
||||
if (host->bus_ops && !host->bus_dead)
|
||||
host->bus_ops->detect(host);
|
||||
|
||||
host->detect_change = 0;
|
||||
|
@ -70,6 +70,8 @@ void mmc_rescan(struct work_struct *work);
|
||||
void mmc_start_host(struct mmc_host *host);
|
||||
void mmc_stop_host(struct mmc_host *host);
|
||||
|
||||
void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
|
||||
bool cd_irq);
|
||||
int _mmc_detect_card_removed(struct mmc_host *host);
|
||||
int mmc_detect_card_removed(struct mmc_host *host);
|
||||
|
||||
|
@ -1048,9 +1048,35 @@ static int mmc_sdio_runtime_resume(struct mmc_host *host)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* SDIO HW reset
|
||||
*
|
||||
* Returns 0 if the HW reset was executed synchronously, returns 1 if the HW
|
||||
* reset was asynchronously scheduled, else a negative error code.
|
||||
*/
|
||||
static int mmc_sdio_hw_reset(struct mmc_host *host)
|
||||
{
|
||||
mmc_power_cycle(host, host->card->ocr);
|
||||
struct mmc_card *card = host->card;
|
||||
|
||||
/*
|
||||
* In case the card is shared among multiple func drivers, reset the
|
||||
* card through a rescan work. In this way it will be removed and
|
||||
* re-detected, thus all func drivers becomes informed about it.
|
||||
*/
|
||||
if (atomic_read(&card->sdio_funcs_probed) > 1) {
|
||||
if (mmc_card_removed(card))
|
||||
return 1;
|
||||
host->rescan_entered = 0;
|
||||
mmc_card_set_removed(card);
|
||||
_mmc_detect_change(host, 0, false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* A single func driver has been probed, then let's skip the heavy
|
||||
* hotplug dance above and execute the reset immediately.
|
||||
*/
|
||||
mmc_power_cycle(host, card->ocr);
|
||||
return mmc_sdio_reinit_card(host);
|
||||
}
|
||||
|
||||
|
@ -138,6 +138,8 @@ static int sdio_bus_probe(struct device *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
atomic_inc(&func->card->sdio_funcs_probed);
|
||||
|
||||
/* Unbound SDIO functions are always suspended.
|
||||
* During probe, the function is set active and the usage count
|
||||
* is incremented. If the driver supports runtime PM,
|
||||
@ -153,7 +155,10 @@ static int sdio_bus_probe(struct device *dev)
|
||||
/* Set the default block size so the driver is sure it's something
|
||||
* sensible. */
|
||||
sdio_claim_host(func);
|
||||
ret = sdio_set_block_size(func, 0);
|
||||
if (mmc_card_removed(func->card))
|
||||
ret = -ENOMEDIUM;
|
||||
else
|
||||
ret = sdio_set_block_size(func, 0);
|
||||
sdio_release_host(func);
|
||||
if (ret)
|
||||
goto disable_runtimepm;
|
||||
@ -165,6 +170,7 @@ static int sdio_bus_probe(struct device *dev)
|
||||
return 0;
|
||||
|
||||
disable_runtimepm:
|
||||
atomic_dec(&func->card->sdio_funcs_probed);
|
||||
if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
|
||||
pm_runtime_put_noidle(dev);
|
||||
dev_pm_domain_detach(dev, false);
|
||||
@ -181,6 +187,7 @@ static int sdio_bus_remove(struct device *dev)
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
drv->remove(func);
|
||||
atomic_dec(&func->card->sdio_funcs_probed);
|
||||
|
||||
if (func->irq_handler) {
|
||||
pr_warn("WARNING: driver %s did not remove its interrupt handler!\n",
|
||||
|
@ -93,8 +93,11 @@
|
||||
#define LINK_SPEED_2_5GTS (1 << 16)
|
||||
#define LINK_SPEED_5_0GTS (2 << 16)
|
||||
#define MACCTLR 0x011058
|
||||
#define MACCTLR_NFTS_MASK GENMASK(23, 16) /* The name is from SH7786 */
|
||||
#define SPEED_CHANGE BIT(24)
|
||||
#define SCRAMBLE_DISABLE BIT(27)
|
||||
#define LTSMDIS BIT(31)
|
||||
#define MACCTLR_INIT_VAL (LTSMDIS | MACCTLR_NFTS_MASK)
|
||||
#define PMSR 0x01105c
|
||||
#define MACS2R 0x011078
|
||||
#define MACCGSPSETR 0x011084
|
||||
@ -615,6 +618,8 @@ static int rcar_pcie_hw_init(struct rcar_pcie *pcie)
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
rcar_pci_write_reg(pcie, 0x801f0000, PCIEMSITXR);
|
||||
|
||||
rcar_pci_write_reg(pcie, MACCTLR_INIT_VAL, MACCTLR);
|
||||
|
||||
/* Finish initialization - establish a PCI Express link */
|
||||
rcar_pci_write_reg(pcie, CFINIT, PCIETCTLR);
|
||||
|
||||
@ -1237,6 +1242,7 @@ static int rcar_pcie_resume_noirq(struct device *dev)
|
||||
return 0;
|
||||
|
||||
/* Re-establish the PCIe link */
|
||||
rcar_pci_write_reg(pcie, MACCTLR_INIT_VAL, MACCTLR);
|
||||
rcar_pci_write_reg(pcie, CFINIT, PCIETCTLR);
|
||||
return rcar_pcie_wait_for_dl(pcie);
|
||||
}
|
||||
|
@ -72,6 +72,7 @@ extern int pciehp_poll_time;
|
||||
* @reset_lock: prevents access to the Data Link Layer Link Active bit in the
|
||||
* Link Status register and to the Presence Detect State bit in the Slot
|
||||
* Status register during a slot reset which may cause them to flap
|
||||
* @ist_running: flag to keep user request waiting while IRQ thread is running
|
||||
* @request_result: result of last user request submitted to the IRQ thread
|
||||
* @requester: wait queue to wake up on completion of user request,
|
||||
* used for synchronous slot enable/disable request via sysfs
|
||||
@ -101,6 +102,7 @@ struct controller {
|
||||
|
||||
struct hotplug_slot hotplug_slot; /* hotplug core interface */
|
||||
struct rw_semaphore reset_lock;
|
||||
unsigned int ist_running;
|
||||
int request_result;
|
||||
wait_queue_head_t requester;
|
||||
};
|
||||
|
@ -375,7 +375,8 @@ int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot)
|
||||
ctrl->request_result = -ENODEV;
|
||||
pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
|
||||
wait_event(ctrl->requester,
|
||||
!atomic_read(&ctrl->pending_events));
|
||||
!atomic_read(&ctrl->pending_events) &&
|
||||
!ctrl->ist_running);
|
||||
return ctrl->request_result;
|
||||
case POWERON_STATE:
|
||||
ctrl_info(ctrl, "Slot(%s): Already in powering on state\n",
|
||||
@ -408,7 +409,8 @@ int pciehp_sysfs_disable_slot(struct hotplug_slot *hotplug_slot)
|
||||
mutex_unlock(&ctrl->state_lock);
|
||||
pciehp_request(ctrl, DISABLE_SLOT);
|
||||
wait_event(ctrl->requester,
|
||||
!atomic_read(&ctrl->pending_events));
|
||||
!atomic_read(&ctrl->pending_events) &&
|
||||
!ctrl->ist_running);
|
||||
return ctrl->request_result;
|
||||
case POWEROFF_STATE:
|
||||
ctrl_info(ctrl, "Slot(%s): Already in powering off state\n",
|
||||
|
@ -583,6 +583,7 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id)
|
||||
irqreturn_t ret;
|
||||
u32 events;
|
||||
|
||||
ctrl->ist_running = true;
|
||||
pci_config_pm_runtime_get(pdev);
|
||||
|
||||
/* rerun pciehp_isr() if the port was inaccessible on interrupt */
|
||||
@ -629,6 +630,7 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id)
|
||||
up_read(&ctrl->reset_lock);
|
||||
|
||||
pci_config_pm_runtime_put(pdev);
|
||||
ctrl->ist_running = false;
|
||||
wake_up(&ctrl->requester);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -213,12 +213,13 @@ u32 __pci_msix_desc_mask_irq(struct msi_desc *desc, u32 flag)
|
||||
|
||||
if (pci_msi_ignore_mask)
|
||||
return 0;
|
||||
|
||||
desc_addr = pci_msix_desc_addr(desc);
|
||||
if (!desc_addr)
|
||||
return 0;
|
||||
|
||||
mask_bits &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT;
|
||||
if (flag)
|
||||
if (flag & PCI_MSIX_ENTRY_CTRL_MASKBIT)
|
||||
mask_bits |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
|
||||
|
||||
writel(mask_bits, desc_addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
|
||||
|
@ -1076,17 +1076,22 @@ static int pci_pm_thaw_noirq(struct device *dev)
|
||||
return error;
|
||||
}
|
||||
|
||||
if (pci_has_legacy_pm_support(pci_dev))
|
||||
return pci_legacy_resume_early(dev);
|
||||
|
||||
/*
|
||||
* pci_restore_state() requires the device to be in D0 (because of MSI
|
||||
* restoration among other things), so force it into D0 in case the
|
||||
* driver's "freeze" callbacks put it into a low-power state directly.
|
||||
* Both the legacy ->resume_early() and the new pm->thaw_noirq()
|
||||
* callbacks assume the device has been returned to D0 and its
|
||||
* config state has been restored.
|
||||
*
|
||||
* In addition, pci_restore_state() restores MSI-X state in MMIO
|
||||
* space, which requires the device to be in D0, so return it to D0
|
||||
* in case the driver's "freeze" callbacks put it into a low-power
|
||||
* state.
|
||||
*/
|
||||
pci_set_power_state(pci_dev, PCI_D0);
|
||||
pci_restore_state(pci_dev);
|
||||
|
||||
if (pci_has_legacy_pm_support(pci_dev))
|
||||
return pci_legacy_resume_early(dev);
|
||||
|
||||
if (drv && drv->pm && drv->pm->thaw_noirq)
|
||||
error = drv->pm->thaw_noirq(dev);
|
||||
|
||||
|
@ -1089,14 +1089,15 @@ static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus,
|
||||
* @sec: updated with secondary bus number from EA
|
||||
* @sub: updated with subordinate bus number from EA
|
||||
*
|
||||
* If @dev is a bridge with EA capability, update @sec and @sub with
|
||||
* fixed bus numbers from the capability and return true. Otherwise,
|
||||
* return false.
|
||||
* If @dev is a bridge with EA capability that specifies valid secondary
|
||||
* and subordinate bus numbers, return true with the bus numbers in @sec
|
||||
* and @sub. Otherwise return false.
|
||||
*/
|
||||
static bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub)
|
||||
{
|
||||
int ea, offset;
|
||||
u32 dw;
|
||||
u8 ea_sec, ea_sub;
|
||||
|
||||
if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE)
|
||||
return false;
|
||||
@ -1108,8 +1109,13 @@ static bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub)
|
||||
|
||||
offset = ea + PCI_EA_FIRST_ENT;
|
||||
pci_read_config_dword(dev, offset, &dw);
|
||||
*sec = dw & PCI_EA_SEC_BUS_MASK;
|
||||
*sub = (dw & PCI_EA_SUB_BUS_MASK) >> PCI_EA_SUB_BUS_SHIFT;
|
||||
ea_sec = dw & PCI_EA_SEC_BUS_MASK;
|
||||
ea_sub = (dw & PCI_EA_SUB_BUS_MASK) >> PCI_EA_SUB_BUS_SHIFT;
|
||||
if (ea_sec == 0 || ea_sub < ea_sec)
|
||||
return false;
|
||||
|
||||
*sec = ea_sec;
|
||||
*sub = ea_sub;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4313,15 +4313,21 @@ static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags)
|
||||
|
||||
static bool pci_quirk_cavium_acs_match(struct pci_dev *dev)
|
||||
{
|
||||
if (!pci_is_pcie(dev) || pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT)
|
||||
return false;
|
||||
|
||||
switch (dev->device) {
|
||||
/*
|
||||
* Effectively selects all downstream ports for whole ThunderX 1
|
||||
* family by 0xf800 mask (which represents 8 SoCs), while the lower
|
||||
* bits of device ID are used to indicate which subdevice is used
|
||||
* within the SoC.
|
||||
* Effectively selects all downstream ports for whole ThunderX1
|
||||
* (which represents 8 SoCs).
|
||||
*/
|
||||
return (pci_is_pcie(dev) &&
|
||||
(pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) &&
|
||||
((dev->device & 0xf800) == 0xa000));
|
||||
case 0xa000 ... 0xa7ff: /* ThunderX1 */
|
||||
case 0xaf84: /* ThunderX2 */
|
||||
case 0xb884: /* ThunderX3 */
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int pci_quirk_cavium_acs(struct pci_dev *dev, u16 acs_flags)
|
||||
@ -4706,7 +4712,7 @@ int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags)
|
||||
#define INTEL_BSPR_REG_BPPD (1 << 9)
|
||||
|
||||
/* Upstream Peer Decode Configuration Register */
|
||||
#define INTEL_UPDCR_REG 0x1114
|
||||
#define INTEL_UPDCR_REG 0x1014
|
||||
/* 5:0 Peer Decode Enable bits */
|
||||
#define INTEL_UPDCR_REG_MASK 0x3f
|
||||
|
||||
|
@ -675,7 +675,7 @@ static int ioctl_event_summary(struct switchtec_dev *stdev,
|
||||
return -ENOMEM;
|
||||
|
||||
s->global = ioread32(&stdev->mmio_sw_event->global_summary);
|
||||
s->part_bitmap = ioread32(&stdev->mmio_sw_event->part_event_bitmap);
|
||||
s->part_bitmap = ioread64(&stdev->mmio_sw_event->part_event_bitmap);
|
||||
s->local_part = ioread32(&stdev->mmio_part_cfg->part_event_summary);
|
||||
|
||||
for (i = 0; i < stdev->partition_count; i++) {
|
||||
|
@ -241,10 +241,31 @@ static void qcom_glink_channel_release(struct kref *ref)
|
||||
{
|
||||
struct glink_channel *channel = container_of(ref, struct glink_channel,
|
||||
refcount);
|
||||
struct glink_core_rx_intent *intent;
|
||||
struct glink_core_rx_intent *tmp;
|
||||
unsigned long flags;
|
||||
int iid;
|
||||
|
||||
/* cancel pending rx_done work */
|
||||
cancel_work_sync(&channel->intent_work);
|
||||
|
||||
spin_lock_irqsave(&channel->intent_lock, flags);
|
||||
/* Free all non-reuse intents pending rx_done work */
|
||||
list_for_each_entry_safe(intent, tmp, &channel->done_intents, node) {
|
||||
if (!intent->reuse) {
|
||||
kfree(intent->data);
|
||||
kfree(intent);
|
||||
}
|
||||
}
|
||||
|
||||
idr_for_each_entry(&channel->liids, tmp, iid) {
|
||||
kfree(tmp->data);
|
||||
kfree(tmp);
|
||||
}
|
||||
idr_destroy(&channel->liids);
|
||||
|
||||
idr_for_each_entry(&channel->riids, tmp, iid)
|
||||
kfree(tmp);
|
||||
idr_destroy(&channel->riids);
|
||||
spin_unlock_irqrestore(&channel->intent_lock, flags);
|
||||
|
||||
@ -1094,13 +1115,12 @@ static int qcom_glink_create_remote(struct qcom_glink *glink,
|
||||
close_link:
|
||||
/*
|
||||
* Send a close request to "undo" our open-ack. The close-ack will
|
||||
* release the last reference.
|
||||
* release qcom_glink_send_open_req() reference and the last reference
|
||||
* will be relesed after receiving remote_close or transport unregister
|
||||
* by calling qcom_glink_native_remove().
|
||||
*/
|
||||
qcom_glink_send_close_req(glink, channel);
|
||||
|
||||
/* Release qcom_glink_send_open_req() reference */
|
||||
kref_put(&channel->refcount, qcom_glink_channel_release);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1415,15 +1435,13 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,
|
||||
|
||||
ret = rpmsg_register_device(rpdev);
|
||||
if (ret)
|
||||
goto free_rpdev;
|
||||
goto rcid_remove;
|
||||
|
||||
channel->rpdev = rpdev;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
free_rpdev:
|
||||
kfree(rpdev);
|
||||
rcid_remove:
|
||||
spin_lock_irqsave(&glink->idr_lock, flags);
|
||||
idr_remove(&glink->rcids, channel->rcid);
|
||||
@ -1544,6 +1562,18 @@ static void qcom_glink_work(struct work_struct *work)
|
||||
}
|
||||
}
|
||||
|
||||
static void qcom_glink_cancel_rx_work(struct qcom_glink *glink)
|
||||
{
|
||||
struct glink_defer_cmd *dcmd;
|
||||
struct glink_defer_cmd *tmp;
|
||||
|
||||
/* cancel any pending deferred rx_work */
|
||||
cancel_work_sync(&glink->rx_work);
|
||||
|
||||
list_for_each_entry_safe(dcmd, tmp, &glink->rx_queue, node)
|
||||
kfree(dcmd);
|
||||
}
|
||||
|
||||
struct qcom_glink *qcom_glink_native_probe(struct device *dev,
|
||||
unsigned long features,
|
||||
struct qcom_glink_pipe *rx,
|
||||
@ -1619,23 +1649,24 @@ void qcom_glink_native_remove(struct qcom_glink *glink)
|
||||
struct glink_channel *channel;
|
||||
int cid;
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
|
||||
disable_irq(glink->irq);
|
||||
cancel_work_sync(&glink->rx_work);
|
||||
qcom_glink_cancel_rx_work(glink);
|
||||
|
||||
ret = device_for_each_child(glink->dev, NULL, qcom_glink_remove_device);
|
||||
if (ret)
|
||||
dev_warn(glink->dev, "Can't remove GLINK devices: %d\n", ret);
|
||||
|
||||
spin_lock_irqsave(&glink->idr_lock, flags);
|
||||
/* Release any defunct local channels, waiting for close-ack */
|
||||
idr_for_each_entry(&glink->lcids, channel, cid)
|
||||
kref_put(&channel->refcount, qcom_glink_channel_release);
|
||||
|
||||
/* Release any defunct local channels, waiting for close-req */
|
||||
idr_for_each_entry(&glink->rcids, channel, cid)
|
||||
kref_put(&channel->refcount, qcom_glink_channel_release);
|
||||
|
||||
idr_destroy(&glink->lcids);
|
||||
idr_destroy(&glink->rcids);
|
||||
spin_unlock_irqrestore(&glink->idr_lock, flags);
|
||||
mbox_free_channel(glink->mbox_chan);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_glink_native_remove);
|
||||
|
@ -105,7 +105,7 @@ static void glink_smem_rx_advance(struct qcom_glink_pipe *np,
|
||||
tail = le32_to_cpu(*pipe->tail);
|
||||
|
||||
tail += count;
|
||||
if (tail > pipe->native.length)
|
||||
if (tail >= pipe->native.length)
|
||||
tail -= pipe->native.length;
|
||||
|
||||
*pipe->tail = cpu_to_le32(tail);
|
||||
|
@ -1945,7 +1945,7 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
|
||||
|
||||
ISCSI_DBG_EH(session, "scsi cmd %p timedout\n", sc);
|
||||
|
||||
spin_lock(&session->frwd_lock);
|
||||
spin_lock_bh(&session->frwd_lock);
|
||||
task = (struct iscsi_task *)sc->SCp.ptr;
|
||||
if (!task) {
|
||||
/*
|
||||
@ -2072,7 +2072,7 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
|
||||
done:
|
||||
if (task)
|
||||
task->last_timeout = jiffies;
|
||||
spin_unlock(&session->frwd_lock);
|
||||
spin_unlock_bh(&session->frwd_lock);
|
||||
ISCSI_DBG_EH(session, "return %s\n", rc == BLK_EH_RESET_TIMER ?
|
||||
"timer reset" : "shutdown or nh");
|
||||
return rc;
|
||||
|
@ -176,6 +176,7 @@ qla2x00_sysfs_read_nvram(struct file *filp, struct kobject *kobj,
|
||||
|
||||
faddr = ha->flt_region_nvram;
|
||||
if (IS_QLA28XX(ha)) {
|
||||
qla28xx_get_aux_images(vha, &active_regions);
|
||||
if (active_regions.aux.vpd_nvram == QLA27XX_SECONDARY_IMAGE)
|
||||
faddr = ha->flt_region_nvram_sec;
|
||||
}
|
||||
|
@ -2399,7 +2399,7 @@ qla2x00_get_flash_image_status(struct bsg_job *bsg_job)
|
||||
struct qla_active_regions regions = { };
|
||||
struct active_regions active_regions = { };
|
||||
|
||||
qla28xx_get_aux_images(vha, &active_regions);
|
||||
qla27xx_get_active_image(vha, &active_regions);
|
||||
regions.global_image = active_regions.global;
|
||||
|
||||
if (IS_QLA28XX(ha)) {
|
||||
|
@ -1523,6 +1523,10 @@ struct qla_flt_header {
|
||||
#define FLT_REG_NVRAM_SEC_28XX_1 0x10F
|
||||
#define FLT_REG_NVRAM_SEC_28XX_2 0x111
|
||||
#define FLT_REG_NVRAM_SEC_28XX_3 0x113
|
||||
#define FLT_REG_MPI_PRI_28XX 0xD3
|
||||
#define FLT_REG_MPI_SEC_28XX 0xF0
|
||||
#define FLT_REG_PEP_PRI_28XX 0xD1
|
||||
#define FLT_REG_PEP_SEC_28XX 0xF1
|
||||
|
||||
struct qla_flt_region {
|
||||
uint16_t code;
|
||||
|
@ -534,6 +534,7 @@ static int qla_post_els_plogi_work(struct scsi_qla_host *vha, fc_port_t *fcport)
|
||||
|
||||
e->u.fcport.fcport = fcport;
|
||||
fcport->flags |= FCF_ASYNC_ACTIVE;
|
||||
fcport->disc_state = DSC_LOGIN_PEND;
|
||||
return qla2x00_post_work(vha, e);
|
||||
}
|
||||
|
||||
@ -4847,6 +4848,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags)
|
||||
}
|
||||
|
||||
INIT_WORK(&fcport->del_work, qla24xx_delete_sess_fn);
|
||||
INIT_WORK(&fcport->free_work, qlt_free_session_done);
|
||||
INIT_WORK(&fcport->reg_work, qla_register_fcport_fn);
|
||||
INIT_LIST_HEAD(&fcport->gnl_entry);
|
||||
INIT_LIST_HEAD(&fcport->list);
|
||||
|
@ -847,15 +847,15 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
|
||||
ha->flt_region_img_status_pri = start;
|
||||
break;
|
||||
case FLT_REG_IMG_SEC_27XX:
|
||||
if (IS_QLA27XX(ha) && !IS_QLA28XX(ha))
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
|
||||
ha->flt_region_img_status_sec = start;
|
||||
break;
|
||||
case FLT_REG_FW_SEC_27XX:
|
||||
if (IS_QLA27XX(ha) && !IS_QLA28XX(ha))
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
|
||||
ha->flt_region_fw_sec = start;
|
||||
break;
|
||||
case FLT_REG_BOOTLOAD_SEC_27XX:
|
||||
if (IS_QLA27XX(ha) && !IS_QLA28XX(ha))
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
|
||||
ha->flt_region_boot_sec = start;
|
||||
break;
|
||||
case FLT_REG_AUX_IMG_PRI_28XX:
|
||||
@ -2725,8 +2725,11 @@ qla28xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
|
||||
ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
|
||||
"Region %x is secure\n", region.code);
|
||||
|
||||
if (region.code == FLT_REG_FW ||
|
||||
region.code == FLT_REG_FW_SEC_27XX) {
|
||||
switch (region.code) {
|
||||
case FLT_REG_FW:
|
||||
case FLT_REG_FW_SEC_27XX:
|
||||
case FLT_REG_MPI_PRI_28XX:
|
||||
case FLT_REG_MPI_SEC_28XX:
|
||||
fw_array = dwptr;
|
||||
|
||||
/* 1st fw array */
|
||||
@ -2757,9 +2760,23 @@ qla28xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
|
||||
buf_size_without_sfub += risc_size;
|
||||
fw_array += risc_size;
|
||||
}
|
||||
} else {
|
||||
ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
|
||||
"Secure region %x not supported\n",
|
||||
break;
|
||||
|
||||
case FLT_REG_PEP_PRI_28XX:
|
||||
case FLT_REG_PEP_SEC_28XX:
|
||||
fw_array = dwptr;
|
||||
|
||||
/* 1st fw array */
|
||||
risc_size = be32_to_cpu(fw_array[3]);
|
||||
risc_attr = be32_to_cpu(fw_array[9]);
|
||||
|
||||
buf_size_without_sfub = risc_size;
|
||||
fw_array += risc_size;
|
||||
break;
|
||||
|
||||
default:
|
||||
ql_log(ql_log_warn + ql_dbg_verbose, vha,
|
||||
0xffff, "Secure region %x not supported\n",
|
||||
region.code);
|
||||
rval = QLA_COMMAND_ERROR;
|
||||
goto done;
|
||||
@ -2880,7 +2897,7 @@ qla28xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
|
||||
"Sending Secure Flash MB Cmd\n");
|
||||
rval = qla28xx_secure_flash_update(vha, 0, region.code,
|
||||
buf_size_without_sfub, sfub_dma,
|
||||
sizeof(struct secure_flash_update_block));
|
||||
sizeof(struct secure_flash_update_block) >> 2);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_log(ql_log_warn, vha, 0xffff,
|
||||
"Secure Flash MB Cmd failed %x.", rval);
|
||||
|
@ -1160,7 +1160,6 @@ void qlt_unreg_sess(struct fc_port *sess)
|
||||
sess->last_rscn_gen = sess->rscn_gen;
|
||||
sess->last_login_gen = sess->login_gen;
|
||||
|
||||
INIT_WORK(&sess->free_work, qlt_free_session_done);
|
||||
queue_work(sess->vha->hw->wq, &sess->free_work);
|
||||
}
|
||||
EXPORT_SYMBOL(qlt_unreg_sess);
|
||||
|
@ -246,6 +246,8 @@ static void tcm_qla2xxx_complete_mcmd(struct work_struct *work)
|
||||
*/
|
||||
static void tcm_qla2xxx_free_mcmd(struct qla_tgt_mgmt_cmd *mcmd)
|
||||
{
|
||||
if (!mcmd)
|
||||
return;
|
||||
INIT_WORK(&mcmd->free_work, tcm_qla2xxx_complete_mcmd);
|
||||
queue_work(tcm_qla2xxx_free_wq, &mcmd->free_work);
|
||||
}
|
||||
|
@ -99,6 +99,12 @@ static int cdns_ufs_link_startup_notify(struct ufs_hba *hba,
|
||||
*/
|
||||
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0);
|
||||
|
||||
/*
|
||||
* Disabling Autohibern8 feature in cadence UFS
|
||||
* to mask unexpected interrupt trigger.
|
||||
*/
|
||||
hba->ahit = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1409,7 +1409,17 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
|
||||
if (usb_endpoint_xfer_control(&urb->ep->desc)) {
|
||||
if (hcd->self.uses_pio_for_control)
|
||||
return ret;
|
||||
if (hcd_uses_dma(hcd)) {
|
||||
if (hcd->localmem_pool) {
|
||||
ret = hcd_alloc_coherent(
|
||||
urb->dev->bus, mem_flags,
|
||||
&urb->setup_dma,
|
||||
(void **)&urb->setup_packet,
|
||||
sizeof(struct usb_ctrlrequest),
|
||||
DMA_TO_DEVICE);
|
||||
if (ret)
|
||||
return ret;
|
||||
urb->transfer_flags |= URB_SETUP_MAP_LOCAL;
|
||||
} else if (hcd_uses_dma(hcd)) {
|
||||
if (is_vmalloc_addr(urb->setup_packet)) {
|
||||
WARN_ONCE(1, "setup packet is not dma capable\n");
|
||||
return -EAGAIN;
|
||||
@ -1427,23 +1437,22 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
|
||||
urb->setup_dma))
|
||||
return -EAGAIN;
|
||||
urb->transfer_flags |= URB_SETUP_MAP_SINGLE;
|
||||
} else if (hcd->localmem_pool) {
|
||||
ret = hcd_alloc_coherent(
|
||||
urb->dev->bus, mem_flags,
|
||||
&urb->setup_dma,
|
||||
(void **)&urb->setup_packet,
|
||||
sizeof(struct usb_ctrlrequest),
|
||||
DMA_TO_DEVICE);
|
||||
if (ret)
|
||||
return ret;
|
||||
urb->transfer_flags |= URB_SETUP_MAP_LOCAL;
|
||||
}
|
||||
}
|
||||
|
||||
dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
|
||||
if (urb->transfer_buffer_length != 0
|
||||
&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
|
||||
if (hcd_uses_dma(hcd)) {
|
||||
if (hcd->localmem_pool) {
|
||||
ret = hcd_alloc_coherent(
|
||||
urb->dev->bus, mem_flags,
|
||||
&urb->transfer_dma,
|
||||
&urb->transfer_buffer,
|
||||
urb->transfer_buffer_length,
|
||||
dir);
|
||||
if (ret == 0)
|
||||
urb->transfer_flags |= URB_MAP_LOCAL;
|
||||
} else if (hcd_uses_dma(hcd)) {
|
||||
if (urb->num_sgs) {
|
||||
int n;
|
||||
|
||||
@ -1497,15 +1506,6 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
|
||||
else
|
||||
urb->transfer_flags |= URB_DMA_MAP_SINGLE;
|
||||
}
|
||||
} else if (hcd->localmem_pool) {
|
||||
ret = hcd_alloc_coherent(
|
||||
urb->dev->bus, mem_flags,
|
||||
&urb->transfer_dma,
|
||||
&urb->transfer_buffer,
|
||||
urb->transfer_buffer_length,
|
||||
dir);
|
||||
if (ret == 0)
|
||||
urb->transfer_flags |= URB_MAP_LOCAL;
|
||||
}
|
||||
if (ret && (urb->transfer_flags & (URB_SETUP_MAP_SINGLE |
|
||||
URB_SETUP_MAP_LOCAL)))
|
||||
|
@ -135,7 +135,8 @@ static int slave_configure(struct scsi_device *sdev)
|
||||
* For such controllers we need to make sure the block layer sets
|
||||
* up bounce buffers in addressable memory.
|
||||
*/
|
||||
if (!hcd_uses_dma(bus_to_hcd(us->pusb_dev->bus)))
|
||||
if (!hcd_uses_dma(bus_to_hcd(us->pusb_dev->bus)) ||
|
||||
(bus_to_hcd(us->pusb_dev->bus)->localmem_pool != NULL))
|
||||
blk_queue_bounce_limit(sdev->request_queue, BLK_BOUNCE_HIGH);
|
||||
|
||||
/*
|
||||
|
@ -294,8 +294,8 @@ static int vfio_msi_set_vector_signal(struct vfio_pci_device *vdev,
|
||||
irq = pci_irq_vector(pdev, vector);
|
||||
|
||||
if (vdev->ctx[vector].trigger) {
|
||||
free_irq(irq, vdev->ctx[vector].trigger);
|
||||
irq_bypass_unregister_producer(&vdev->ctx[vector].producer);
|
||||
free_irq(irq, vdev->ctx[vector].trigger);
|
||||
kfree(vdev->ctx[vector].name);
|
||||
eventfd_ctx_put(vdev->ctx[vector].trigger);
|
||||
vdev->ctx[vector].trigger = NULL;
|
||||
|
@ -256,6 +256,11 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
|
||||
if (!server->rdma)
|
||||
goto skip_rdma;
|
||||
|
||||
if (!server->smbd_conn) {
|
||||
seq_printf(m, "\nSMBDirect transport not available");
|
||||
goto skip_rdma;
|
||||
}
|
||||
|
||||
seq_printf(m, "\nSMBDirect (in hex) protocol version: %x "
|
||||
"transport status: %x",
|
||||
server->smbd_conn->protocol,
|
||||
|
@ -1524,6 +1524,7 @@ struct mid_q_entry {
|
||||
struct TCP_Server_Info *server; /* server corresponding to this mid */
|
||||
__u64 mid; /* multiplex id */
|
||||
__u16 credits; /* number of credits consumed by this mid */
|
||||
__u16 credits_received; /* number of credits from the response */
|
||||
__u32 pid; /* process id */
|
||||
__u32 sequence_number; /* for CIFS signing */
|
||||
unsigned long when_alloc; /* when mid was created */
|
||||
|
@ -905,6 +905,20 @@ dequeue_mid(struct mid_q_entry *mid, bool malformed)
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
smb2_get_credits_from_hdr(char *buffer, struct TCP_Server_Info *server)
|
||||
{
|
||||
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buffer;
|
||||
|
||||
/*
|
||||
* SMB1 does not use credits.
|
||||
*/
|
||||
if (server->vals->header_preamble_size)
|
||||
return 0;
|
||||
|
||||
return le16_to_cpu(shdr->CreditRequest);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
|
||||
char *buf, int malformed)
|
||||
@ -912,6 +926,7 @@ handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
|
||||
if (server->ops->check_trans2 &&
|
||||
server->ops->check_trans2(mid, server, buf, malformed))
|
||||
return;
|
||||
mid->credits_received = smb2_get_credits_from_hdr(buf, server);
|
||||
mid->resp_buf = buf;
|
||||
mid->large_buf = server->large_buf;
|
||||
/* Was previous buf put in mpx struct for multi-rsp? */
|
||||
@ -1222,12 +1237,6 @@ next_pdu:
|
||||
for (i = 0; i < num_mids; i++) {
|
||||
if (mids[i] != NULL) {
|
||||
mids[i]->resp_buf_size = server->pdu_size;
|
||||
if ((mids[i]->mid_flags & MID_WAIT_CANCELLED) &&
|
||||
mids[i]->mid_state == MID_RESPONSE_RECEIVED &&
|
||||
server->ops->handle_cancelled_mid)
|
||||
server->ops->handle_cancelled_mid(
|
||||
mids[i]->resp_buf,
|
||||
server);
|
||||
|
||||
if (!mids[i]->multiRsp || mids[i]->multiEnd)
|
||||
mids[i]->callback(mids[i]);
|
||||
@ -4700,6 +4709,17 @@ static int is_path_remote(struct cifs_sb_info *cifs_sb, struct smb_vol *vol,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
static inline void set_root_tcon(struct cifs_sb_info *cifs_sb,
|
||||
struct cifs_tcon *tcon,
|
||||
struct cifs_tcon **root)
|
||||
{
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
tcon->tc_count++;
|
||||
tcon->remap = cifs_remap(cifs_sb);
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
*root = tcon;
|
||||
}
|
||||
|
||||
int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol)
|
||||
{
|
||||
int rc = 0;
|
||||
@ -4801,18 +4821,10 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol)
|
||||
/* Cache out resolved root server */
|
||||
(void)dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb),
|
||||
root_path + 1, NULL, NULL);
|
||||
/*
|
||||
* Save root tcon for additional DFS requests to update or create a new
|
||||
* DFS cache entry, or even perform DFS failover.
|
||||
*/
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
tcon->tc_count++;
|
||||
tcon->dfs_path = root_path;
|
||||
kfree(root_path);
|
||||
root_path = NULL;
|
||||
tcon->remap = cifs_remap(cifs_sb);
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
root_tcon = tcon;
|
||||
set_root_tcon(cifs_sb, tcon, &root_tcon);
|
||||
|
||||
for (count = 1; ;) {
|
||||
if (!rc && tcon) {
|
||||
@ -4849,6 +4861,15 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol)
|
||||
mount_put_conns(cifs_sb, xid, server, ses, tcon);
|
||||
rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses,
|
||||
&tcon);
|
||||
/*
|
||||
* Ensure that DFS referrals go through new root server.
|
||||
*/
|
||||
if (!rc && tcon &&
|
||||
(tcon->share_flags & (SHI1005_FLAGS_DFS |
|
||||
SHI1005_FLAGS_DFS_ROOT))) {
|
||||
cifs_put_tcon(root_tcon);
|
||||
set_root_tcon(cifs_sb, tcon, &root_tcon);
|
||||
}
|
||||
}
|
||||
if (rc) {
|
||||
if (rc == -EACCES || rc == -EOPNOTSUPP)
|
||||
|
@ -729,6 +729,13 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
|
||||
if (backup_cred(cifs_sb))
|
||||
create_options |= CREATE_OPEN_BACKUP_INTENT;
|
||||
|
||||
/* O_SYNC also has bit for O_DSYNC so following check picks up either */
|
||||
if (cfile->f_flags & O_SYNC)
|
||||
create_options |= CREATE_WRITE_THROUGH;
|
||||
|
||||
if (cfile->f_flags & O_DIRECT)
|
||||
create_options |= CREATE_NO_BUFFER;
|
||||
|
||||
if (server->ops->get_lease_key)
|
||||
server->ops->get_lease_key(inode, &cfile->fid);
|
||||
|
||||
|
@ -743,36 +743,67 @@ smb2_cancelled_close_fid(struct work_struct *work)
|
||||
kfree(cancelled);
|
||||
}
|
||||
|
||||
/* Caller should already has an extra reference to @tcon */
|
||||
static int
|
||||
__smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid,
|
||||
__u64 volatile_fid)
|
||||
{
|
||||
struct close_cancelled_open *cancelled;
|
||||
|
||||
cancelled = kzalloc(sizeof(*cancelled), GFP_KERNEL);
|
||||
if (!cancelled)
|
||||
return -ENOMEM;
|
||||
|
||||
cancelled->fid.persistent_fid = persistent_fid;
|
||||
cancelled->fid.volatile_fid = volatile_fid;
|
||||
cancelled->tcon = tcon;
|
||||
INIT_WORK(&cancelled->work, smb2_cancelled_close_fid);
|
||||
WARN_ON(queue_work(cifsiod_wq, &cancelled->work) == false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid,
|
||||
__u64 volatile_fid)
|
||||
{
|
||||
int rc;
|
||||
|
||||
cifs_dbg(FYI, "%s: tc_count=%d\n", __func__, tcon->tc_count);
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
tcon->tc_count++;
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
rc = __smb2_handle_cancelled_close(tcon, persistent_fid, volatile_fid);
|
||||
if (rc)
|
||||
cifs_put_tcon(tcon);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
smb2_handle_cancelled_mid(char *buffer, struct TCP_Server_Info *server)
|
||||
{
|
||||
struct smb2_sync_hdr *sync_hdr = (struct smb2_sync_hdr *)buffer;
|
||||
struct smb2_create_rsp *rsp = (struct smb2_create_rsp *)buffer;
|
||||
struct cifs_tcon *tcon;
|
||||
struct close_cancelled_open *cancelled;
|
||||
int rc;
|
||||
|
||||
if (sync_hdr->Command != SMB2_CREATE ||
|
||||
sync_hdr->Status != STATUS_SUCCESS)
|
||||
return 0;
|
||||
|
||||
cancelled = kzalloc(sizeof(*cancelled), GFP_KERNEL);
|
||||
if (!cancelled)
|
||||
return -ENOMEM;
|
||||
|
||||
tcon = smb2_find_smb_tcon(server, sync_hdr->SessionId,
|
||||
sync_hdr->TreeId);
|
||||
if (!tcon) {
|
||||
kfree(cancelled);
|
||||
if (!tcon)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
cancelled->fid.persistent_fid = rsp->PersistentFileId;
|
||||
cancelled->fid.volatile_fid = rsp->VolatileFileId;
|
||||
cancelled->tcon = tcon;
|
||||
INIT_WORK(&cancelled->work, smb2_cancelled_close_fid);
|
||||
queue_work(cifsiod_wq, &cancelled->work);
|
||||
rc = __smb2_handle_cancelled_close(tcon, rsp->PersistentFileId,
|
||||
rsp->VolatileFileId);
|
||||
if (rc)
|
||||
cifs_put_tcon(tcon);
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -151,13 +151,7 @@ smb2_get_credits_field(struct TCP_Server_Info *server, const int optype)
|
||||
static unsigned int
|
||||
smb2_get_credits(struct mid_q_entry *mid)
|
||||
{
|
||||
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)mid->resp_buf;
|
||||
|
||||
if (mid->mid_state == MID_RESPONSE_RECEIVED
|
||||
|| mid->mid_state == MID_RESPONSE_MALFORMED)
|
||||
return le16_to_cpu(shdr->CreditRequest);
|
||||
|
||||
return 0;
|
||||
return mid->credits_received;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -2972,7 +2972,21 @@ int
|
||||
SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid)
|
||||
{
|
||||
return SMB2_close_flags(xid, tcon, persistent_fid, volatile_fid, 0);
|
||||
int rc;
|
||||
int tmp_rc;
|
||||
|
||||
rc = SMB2_close_flags(xid, tcon, persistent_fid, volatile_fid, 0);
|
||||
|
||||
/* retry close in a worker thread if this one is interrupted */
|
||||
if (rc == -EINTR) {
|
||||
tmp_rc = smb2_handle_cancelled_close(tcon, persistent_fid,
|
||||
volatile_fid);
|
||||
if (tmp_rc)
|
||||
cifs_dbg(VFS, "handle cancelled close fid 0x%llx returned error %d\n",
|
||||
persistent_fid, tmp_rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -212,6 +212,9 @@ extern int SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const u64 persistent_fid, const u64 volatile_fid,
|
||||
const __u8 oplock_level);
|
||||
extern int smb2_handle_cancelled_close(struct cifs_tcon *tcon,
|
||||
__u64 persistent_fid,
|
||||
__u64 volatile_fid);
|
||||
extern int smb2_handle_cancelled_mid(char *buffer,
|
||||
struct TCP_Server_Info *server);
|
||||
void smb2_cancelled_close_fid(struct work_struct *work);
|
||||
|
@ -1069,7 +1069,7 @@ static int smbd_post_send_data(
|
||||
|
||||
if (n_vec > SMBDIRECT_MAX_SGE) {
|
||||
cifs_dbg(VFS, "Can't fit data to SGL, n_vec=%d\n", n_vec);
|
||||
return -ENOMEM;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sg_init_table(sgl, n_vec);
|
||||
@ -1476,6 +1476,7 @@ void smbd_destroy(struct TCP_Server_Info *server)
|
||||
info->transport_status = SMBD_DESTROYED;
|
||||
|
||||
destroy_workqueue(info->workqueue);
|
||||
log_rdma_event(INFO, "rdma session destroyed\n");
|
||||
kfree(info);
|
||||
}
|
||||
|
||||
@ -1505,8 +1506,9 @@ create_conn:
|
||||
log_rdma_event(INFO, "creating rdma session\n");
|
||||
server->smbd_conn = smbd_get_connection(
|
||||
server, (struct sockaddr *) &server->dstaddr);
|
||||
log_rdma_event(INFO, "created rdma session info=%p\n",
|
||||
server->smbd_conn);
|
||||
|
||||
if (server->smbd_conn)
|
||||
cifs_dbg(VFS, "RDMA transport re-established\n");
|
||||
|
||||
return server->smbd_conn ? 0 : -ENOENT;
|
||||
}
|
||||
@ -1970,7 +1972,7 @@ read_rfc1002_done:
|
||||
|
||||
if (info->transport_status != SMBD_CONNECTED) {
|
||||
log_read(ERR, "disconnected\n");
|
||||
return 0;
|
||||
return -ECONNABORTED;
|
||||
}
|
||||
|
||||
goto again;
|
||||
@ -2269,12 +2271,7 @@ static void smbd_mr_recovery_work(struct work_struct *work)
|
||||
int rc;
|
||||
|
||||
list_for_each_entry(smbdirect_mr, &info->mr_list, list) {
|
||||
if (smbdirect_mr->state == MR_INVALIDATED)
|
||||
ib_dma_unmap_sg(
|
||||
info->id->device, smbdirect_mr->sgl,
|
||||
smbdirect_mr->sgl_count,
|
||||
smbdirect_mr->dir);
|
||||
else if (smbdirect_mr->state == MR_ERROR) {
|
||||
if (smbdirect_mr->state == MR_ERROR) {
|
||||
|
||||
/* recover this MR entry */
|
||||
rc = ib_dereg_mr(smbdirect_mr->mr);
|
||||
@ -2602,11 +2599,20 @@ int smbd_deregister_mr(struct smbd_mr *smbdirect_mr)
|
||||
*/
|
||||
smbdirect_mr->state = MR_INVALIDATED;
|
||||
|
||||
/*
|
||||
* Schedule the work to do MR recovery for future I/Os
|
||||
* MR recovery is slow and we don't want it to block the current I/O
|
||||
*/
|
||||
queue_work(info->workqueue, &info->mr_recovery_work);
|
||||
if (smbdirect_mr->state == MR_INVALIDATED) {
|
||||
ib_dma_unmap_sg(
|
||||
info->id->device, smbdirect_mr->sgl,
|
||||
smbdirect_mr->sgl_count,
|
||||
smbdirect_mr->dir);
|
||||
smbdirect_mr->state = MR_READY;
|
||||
if (atomic_inc_return(&info->mr_ready_count) == 1)
|
||||
wake_up_interruptible(&info->wait_mr);
|
||||
} else
|
||||
/*
|
||||
* Schedule the work to do MR recovery for future I/Os MR
|
||||
* recovery is slow and don't want it to block current I/O
|
||||
*/
|
||||
queue_work(info->workqueue, &info->mr_recovery_work);
|
||||
|
||||
done:
|
||||
if (atomic_dec_and_test(&info->mr_used_count))
|
||||
|
@ -93,8 +93,14 @@ static void _cifs_mid_q_entry_release(struct kref *refcount)
|
||||
__u16 smb_cmd = le16_to_cpu(midEntry->command);
|
||||
unsigned long now;
|
||||
unsigned long roundtrip_time;
|
||||
struct TCP_Server_Info *server = midEntry->server;
|
||||
#endif
|
||||
struct TCP_Server_Info *server = midEntry->server;
|
||||
|
||||
if (midEntry->resp_buf && (midEntry->mid_flags & MID_WAIT_CANCELLED) &&
|
||||
midEntry->mid_state == MID_RESPONSE_RECEIVED &&
|
||||
server->ops->handle_cancelled_mid)
|
||||
server->ops->handle_cancelled_mid(midEntry->resp_buf, server);
|
||||
|
||||
midEntry->mid_state = MID_FREE;
|
||||
atomic_dec(&midCount);
|
||||
if (midEntry->large_buf)
|
||||
@ -319,8 +325,11 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
|
||||
int val = 1;
|
||||
__be32 rfc1002_marker;
|
||||
|
||||
if (cifs_rdma_enabled(server) && server->smbd_conn) {
|
||||
rc = smbd_send(server, num_rqst, rqst);
|
||||
if (cifs_rdma_enabled(server)) {
|
||||
/* return -EAGAIN when connecting or reconnecting */
|
||||
rc = -EAGAIN;
|
||||
if (server->smbd_conn)
|
||||
rc = smbd_send(server, num_rqst, rqst);
|
||||
goto smbd_done;
|
||||
}
|
||||
|
||||
@ -1119,8 +1128,8 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
||||
midQ[i]->mid, le16_to_cpu(midQ[i]->command));
|
||||
send_cancel(server, &rqst[i], midQ[i]);
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
midQ[i]->mid_flags |= MID_WAIT_CANCELLED;
|
||||
if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED) {
|
||||
midQ[i]->mid_flags |= MID_WAIT_CANCELLED;
|
||||
midQ[i]->callback = cifs_cancelled_callback;
|
||||
cancelled_mid[i] = true;
|
||||
credits[i].value = 0;
|
||||
|
@ -381,27 +381,28 @@ static void gfs2_size_hint(struct file *filep, loff_t offset, size_t size)
|
||||
/**
|
||||
* gfs2_allocate_page_backing - Allocate blocks for a write fault
|
||||
* @page: The (locked) page to allocate backing for
|
||||
* @length: Size of the allocation
|
||||
*
|
||||
* We try to allocate all the blocks required for the page in one go. This
|
||||
* might fail for various reasons, so we keep trying until all the blocks to
|
||||
* back this page are allocated. If some of the blocks are already allocated,
|
||||
* that is ok too.
|
||||
*/
|
||||
static int gfs2_allocate_page_backing(struct page *page)
|
||||
static int gfs2_allocate_page_backing(struct page *page, unsigned int length)
|
||||
{
|
||||
u64 pos = page_offset(page);
|
||||
u64 size = PAGE_SIZE;
|
||||
|
||||
do {
|
||||
struct iomap iomap = { };
|
||||
|
||||
if (gfs2_iomap_get_alloc(page->mapping->host, pos, 1, &iomap))
|
||||
if (gfs2_iomap_get_alloc(page->mapping->host, pos, length, &iomap))
|
||||
return -EIO;
|
||||
|
||||
iomap.length = min(iomap.length, size);
|
||||
size -= iomap.length;
|
||||
if (length < iomap.length)
|
||||
iomap.length = length;
|
||||
length -= iomap.length;
|
||||
pos += iomap.length;
|
||||
} while (size > 0);
|
||||
} while (length > 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -501,7 +502,7 @@ static vm_fault_t gfs2_page_mkwrite(struct vm_fault *vmf)
|
||||
if (gfs2_is_stuffed(ip))
|
||||
ret = gfs2_unstuff_dinode(ip, page);
|
||||
if (ret == 0)
|
||||
ret = gfs2_allocate_page_backing(page);
|
||||
ret = gfs2_allocate_page_backing(page, PAGE_SIZE);
|
||||
|
||||
out_trans_end:
|
||||
if (ret)
|
||||
|
@ -609,6 +609,14 @@ void gfs2_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd)
|
||||
list_add(&bd->bd_list, &sdp->sd_log_revokes);
|
||||
}
|
||||
|
||||
void gfs2_glock_remove_revoke(struct gfs2_glock *gl)
|
||||
{
|
||||
if (atomic_dec_return(&gl->gl_revokes) == 0) {
|
||||
clear_bit(GLF_LFLUSH, &gl->gl_flags);
|
||||
gfs2_glock_queue_put(gl);
|
||||
}
|
||||
}
|
||||
|
||||
void gfs2_write_revokes(struct gfs2_sbd *sdp)
|
||||
{
|
||||
struct gfs2_trans *tr;
|
||||
|
@ -77,6 +77,7 @@ extern void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc)
|
||||
extern void gfs2_log_shutdown(struct gfs2_sbd *sdp);
|
||||
extern int gfs2_logd(void *data);
|
||||
extern void gfs2_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd);
|
||||
extern void gfs2_glock_remove_revoke(struct gfs2_glock *gl);
|
||||
extern void gfs2_write_revokes(struct gfs2_sbd *sdp);
|
||||
|
||||
#endif /* __LOG_DOT_H__ */
|
||||
|
@ -882,10 +882,7 @@ static void revoke_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
|
||||
bd = list_entry(head->next, struct gfs2_bufdata, bd_list);
|
||||
list_del_init(&bd->bd_list);
|
||||
gl = bd->bd_gl;
|
||||
if (atomic_dec_return(&gl->gl_revokes) == 0) {
|
||||
clear_bit(GLF_LFLUSH, &gl->gl_flags);
|
||||
gfs2_glock_queue_put(gl);
|
||||
}
|
||||
gfs2_glock_remove_revoke(gl);
|
||||
kmem_cache_free(gfs2_bufdata_cachep, bd);
|
||||
}
|
||||
}
|
||||
|
@ -262,6 +262,8 @@ void gfs2_trans_remove_revoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len)
|
||||
list_del_init(&bd->bd_list);
|
||||
gfs2_assert_withdraw(sdp, sdp->sd_log_num_revoke);
|
||||
sdp->sd_log_num_revoke--;
|
||||
if (bd->bd_gl)
|
||||
gfs2_glock_remove_revoke(bd->bd_gl);
|
||||
kmem_cache_free(gfs2_bufdata_cachep, bd);
|
||||
tr->tr_num_revoke--;
|
||||
if (--n == 0)
|
||||
|
@ -291,6 +291,7 @@ struct mmc_card {
|
||||
struct sd_switch_caps sw_caps; /* switch (CMD6) caps */
|
||||
|
||||
unsigned int sdio_funcs; /* number of SDIO functions */
|
||||
atomic_t sdio_funcs_probed; /* number of probed SDIO funcs */
|
||||
struct sdio_cccr cccr; /* common card info */
|
||||
struct sdio_cis cis; /* common tuple info */
|
||||
struct sdio_func *sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */
|
||||
|
@ -256,7 +256,7 @@ static inline s32 dev_pm_qos_raw_resume_latency(struct device *dev)
|
||||
#endif
|
||||
|
||||
#define FREQ_QOS_MIN_DEFAULT_VALUE 0
|
||||
#define FREQ_QOS_MAX_DEFAULT_VALUE (-1)
|
||||
#define FREQ_QOS_MAX_DEFAULT_VALUE S32_MAX
|
||||
|
||||
enum freq_qos_req_type {
|
||||
FREQ_QOS_MIN = 1,
|
||||
|
@ -120,10 +120,8 @@ void snd_hdac_stream_clear(struct hdac_stream *azx_dev)
|
||||
snd_hdac_stream_updateb(azx_dev, SD_CTL,
|
||||
SD_CTL_DMA_START | SD_INT_MASK, 0);
|
||||
snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */
|
||||
if (azx_dev->stripe) {
|
||||
if (azx_dev->stripe)
|
||||
snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0);
|
||||
azx_dev->stripe = 0;
|
||||
}
|
||||
azx_dev->running = false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_stream_clear);
|
||||
|
@ -1983,6 +1983,8 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
|
||||
per_cvt->assigned = 0;
|
||||
hinfo->nid = 0;
|
||||
|
||||
azx_stream(get_azx_dev(substream))->stripe = 0;
|
||||
|
||||
mutex_lock(&spec->pcm_lock);
|
||||
snd_hda_spdif_ctls_unassign(codec, pcm_idx);
|
||||
clear_bit(pcm_idx, &spec->pcm_in_use);
|
||||
|
Loading…
Reference in New Issue
Block a user