Linux 4.4-rc4
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJWZMgaAAoJEHm+PkMAQRiGGcIH+gNS/hbN2DKW7wphl1QuaV7C 1fror8AvpwbGa/o0yuxovaVuZzAR0TF31vn+gAemF4U/hnM25xqxEHXYZEVv8OWw mbz4/z+jbVk3SiS5AiZPIZgL4W6RZnG5QYfiTVGPlBHuBznW2ITlNlClBOmBL45o uhb3bjTzi70AZ7Gh6i9sHgJoHg6D9u/ZxLaLcWnM79BzyTMHTf2t0wnrQmh66lEE hp7Rn9wXv9bk/e3iH7CVUb97P4IWhhkmfqcoturqAg9+C/M26b0VmvQp9Sy8S6Pd FVQ+SUIZllj5ZDKe9mOcs37czlxTr0keEFqzWeMh/7y4iuI3RaRp/qb+7mX5sIE= =WGZ1 -----END PGP SIGNATURE----- Back merge tag 'v4.4-rc4' into drm-next We've picked up a few conflicts and it would be nice to resolve them before we move onwards.
This commit is contained in:
		
						commit
						e876b41ab0
					
				| @ -8,6 +8,11 @@ Required properties: | ||||
| - phy-mode: See ethernet.txt file in the same directory | ||||
| - clocks: a pointer to the reference clock for this device. | ||||
| 
 | ||||
| Optional properties: | ||||
| - tx-csum-limit: maximum mtu supported by port that allow TX checksum. | ||||
|   Value is presented in bytes. If not used, by default 1600B is set for | ||||
|   "marvell,armada-370-neta" and 9800B for others. | ||||
| 
 | ||||
| Example: | ||||
| 
 | ||||
| ethernet@d0070000 { | ||||
| @ -15,6 +20,7 @@ ethernet@d0070000 { | ||||
| 	reg = <0xd0070000 0x2500>; | ||||
| 	interrupts = <8>; | ||||
| 	clocks = <&gate_clk 4>; | ||||
| 	tx-csum-limit = <9800> | ||||
| 	status = "okay"; | ||||
| 	phy = <&phy0>; | ||||
| 	phy-mode = "rgmii-id"; | ||||
|  | ||||
							
								
								
									
										12
									
								
								MAINTAINERS
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								MAINTAINERS
									
									
									
									
									
								
							| @ -318,7 +318,7 @@ M:	Zhang Rui <rui.zhang@intel.com> | ||||
| L:	linux-acpi@vger.kernel.org | ||||
| W:	https://01.org/linux-acpi | ||||
| S:	Supported | ||||
| F:	drivers/acpi/video.c | ||||
| F:	drivers/acpi/acpi_video.c | ||||
| 
 | ||||
| ACPI WMI DRIVER | ||||
| L:	platform-driver-x86@vger.kernel.org | ||||
| @ -1847,7 +1847,7 @@ S:	Supported | ||||
| F:	drivers/net/wireless/ath/ath6kl/ | ||||
| 
 | ||||
| WILOCITY WIL6210 WIRELESS DRIVER | ||||
| M:	Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com> | ||||
| M:	Maya Erez <qca_merez@qca.qualcomm.com> | ||||
| L:	linux-wireless@vger.kernel.org | ||||
| L:	wil6210@qca.qualcomm.com | ||||
| S:	Supported | ||||
| @ -9427,8 +9427,10 @@ F:	include/scsi/sg.h | ||||
| 
 | ||||
| SCSI SUBSYSTEM | ||||
| M:	"James E.J. Bottomley" <JBottomley@odin.com> | ||||
| L:	linux-scsi@vger.kernel.org | ||||
| T:	git git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git | ||||
| M:	"Martin K. Petersen" <martin.petersen@oracle.com> | ||||
| T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git | ||||
| L:	linux-scsi@vger.kernel.org | ||||
| S:	Maintained | ||||
| F:	drivers/scsi/ | ||||
| F:	include/scsi/ | ||||
| @ -10903,9 +10905,9 @@ S:	Maintained | ||||
| F:	drivers/media/tuners/tua9001* | ||||
| 
 | ||||
| TULIP NETWORK DRIVERS | ||||
| M:	Grant Grundler <grundler@parisc-linux.org> | ||||
| L:	netdev@vger.kernel.org | ||||
| S:	Maintained | ||||
| L:	linux-parisc@vger.kernel.org | ||||
| S:	Orphan | ||||
| F:	drivers/net/ethernet/dec/tulip/ | ||||
| 
 | ||||
| TUN/TAP driver | ||||
|  | ||||
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @ -1,7 +1,7 @@ | ||||
| VERSION = 4 | ||||
| PATCHLEVEL = 4 | ||||
| SUBLEVEL = 0 | ||||
| EXTRAVERSION = -rc3 | ||||
| EXTRAVERSION = -rc4 | ||||
| NAME = Blurry Fish Butt | ||||
| 
 | ||||
| # *DOCUMENTATION*
 | ||||
|  | ||||
| @ -498,6 +498,7 @@ | ||||
| 				reg = <0x70000 0x4000>; | ||||
| 				interrupts-extended = <&mpic 8>; | ||||
| 				clocks = <&gateclk 4>; | ||||
| 				tx-csum-limit = <9800>; | ||||
| 				status = "disabled"; | ||||
| 			}; | ||||
| 
 | ||||
|  | ||||
| @ -28,6 +28,18 @@ | ||||
| unsigned long *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num); | ||||
| unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu); | ||||
| 
 | ||||
| static inline unsigned long vcpu_get_reg(struct kvm_vcpu *vcpu, | ||||
| 					 u8 reg_num) | ||||
| { | ||||
| 	return *vcpu_reg(vcpu, reg_num); | ||||
| } | ||||
| 
 | ||||
| static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num, | ||||
| 				unsigned long val) | ||||
| { | ||||
| 	*vcpu_reg(vcpu, reg_num) = val; | ||||
| } | ||||
| 
 | ||||
| bool kvm_condition_valid(struct kvm_vcpu *vcpu); | ||||
| void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr); | ||||
| void kvm_inject_undefined(struct kvm_vcpu *vcpu); | ||||
|  | ||||
| @ -115,7 +115,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||||
| 		trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr, | ||||
| 			       data); | ||||
| 		data = vcpu_data_host_to_guest(vcpu, data, len); | ||||
| 		*vcpu_reg(vcpu, vcpu->arch.mmio_decode.rt) = data; | ||||
| 		vcpu_set_reg(vcpu, vcpu->arch.mmio_decode.rt, data); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| @ -186,7 +186,8 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run, | ||||
| 	rt = vcpu->arch.mmio_decode.rt; | ||||
| 
 | ||||
| 	if (is_write) { | ||||
| 		data = vcpu_data_guest_to_host(vcpu, *vcpu_reg(vcpu, rt), len); | ||||
| 		data = vcpu_data_guest_to_host(vcpu, vcpu_get_reg(vcpu, rt), | ||||
| 					       len); | ||||
| 
 | ||||
| 		trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, data); | ||||
| 		mmio_write_buf(data_buf, len, data); | ||||
|  | ||||
| @ -218,7 +218,7 @@ static void unmap_ptes(struct kvm *kvm, pmd_t *pmd, | ||||
| 			kvm_tlb_flush_vmid_ipa(kvm, addr); | ||||
| 
 | ||||
| 			/* No need to invalidate the cache for device mappings */ | ||||
| 			if (!kvm_is_device_pfn(__phys_to_pfn(addr))) | ||||
| 			if (!kvm_is_device_pfn(pte_pfn(old_pte))) | ||||
| 				kvm_flush_dcache_pte(old_pte); | ||||
| 
 | ||||
| 			put_page(virt_to_page(pte)); | ||||
| @ -310,7 +310,7 @@ static void stage2_flush_ptes(struct kvm *kvm, pmd_t *pmd, | ||||
| 
 | ||||
| 	pte = pte_offset_kernel(pmd, addr); | ||||
| 	do { | ||||
| 		if (!pte_none(*pte) && !kvm_is_device_pfn(__phys_to_pfn(addr))) | ||||
| 		if (!pte_none(*pte) && !kvm_is_device_pfn(pte_pfn(*pte))) | ||||
| 			kvm_flush_dcache_pte(*pte); | ||||
| 	} while (pte++, addr += PAGE_SIZE, addr != end); | ||||
| } | ||||
|  | ||||
| @ -75,7 +75,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) | ||||
| 	unsigned long context_id; | ||||
| 	phys_addr_t target_pc; | ||||
| 
 | ||||
| 	cpu_id = *vcpu_reg(source_vcpu, 1) & MPIDR_HWID_BITMASK; | ||||
| 	cpu_id = vcpu_get_reg(source_vcpu, 1) & MPIDR_HWID_BITMASK; | ||||
| 	if (vcpu_mode_is_32bit(source_vcpu)) | ||||
| 		cpu_id &= ~((u32) 0); | ||||
| 
 | ||||
| @ -94,8 +94,8 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) | ||||
| 			return PSCI_RET_INVALID_PARAMS; | ||||
| 	} | ||||
| 
 | ||||
| 	target_pc = *vcpu_reg(source_vcpu, 2); | ||||
| 	context_id = *vcpu_reg(source_vcpu, 3); | ||||
| 	target_pc = vcpu_get_reg(source_vcpu, 2); | ||||
| 	context_id = vcpu_get_reg(source_vcpu, 3); | ||||
| 
 | ||||
| 	kvm_reset_vcpu(vcpu); | ||||
| 
 | ||||
| @ -114,7 +114,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) | ||||
| 	 * NOTE: We always update r0 (or x0) because for PSCI v0.1 | ||||
| 	 * the general puspose registers are undefined upon CPU_ON. | ||||
| 	 */ | ||||
| 	*vcpu_reg(vcpu, 0) = context_id; | ||||
| 	vcpu_set_reg(vcpu, 0, context_id); | ||||
| 	vcpu->arch.power_off = false; | ||||
| 	smp_mb();		/* Make sure the above is visible */ | ||||
| 
 | ||||
| @ -134,8 +134,8 @@ static unsigned long kvm_psci_vcpu_affinity_info(struct kvm_vcpu *vcpu) | ||||
| 	struct kvm *kvm = vcpu->kvm; | ||||
| 	struct kvm_vcpu *tmp; | ||||
| 
 | ||||
| 	target_affinity = *vcpu_reg(vcpu, 1); | ||||
| 	lowest_affinity_level = *vcpu_reg(vcpu, 2); | ||||
| 	target_affinity = vcpu_get_reg(vcpu, 1); | ||||
| 	lowest_affinity_level = vcpu_get_reg(vcpu, 2); | ||||
| 
 | ||||
| 	/* Determine target affinity mask */ | ||||
| 	target_affinity_mask = psci_affinity_mask(lowest_affinity_level); | ||||
| @ -209,7 +209,7 @@ int kvm_psci_version(struct kvm_vcpu *vcpu) | ||||
| static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	int ret = 1; | ||||
| 	unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0); | ||||
| 	unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0); | ||||
| 	unsigned long val; | ||||
| 
 | ||||
| 	switch (psci_fn) { | ||||
| @ -273,13 +273,13 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu) | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	*vcpu_reg(vcpu, 0) = val; | ||||
| 	vcpu_set_reg(vcpu, 0, val); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0); | ||||
| 	unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0); | ||||
| 	unsigned long val; | ||||
| 
 | ||||
| 	switch (psci_fn) { | ||||
| @ -295,7 +295,7 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu) | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	*vcpu_reg(vcpu, 0) = val; | ||||
| 	vcpu_set_reg(vcpu, 0, val); | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -100,13 +100,21 @@ static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu) | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * vcpu_reg should always be passed a register number coming from a | ||||
|  * read of ESR_EL2. Otherwise, it may give the wrong result on AArch32 | ||||
|  * with banked registers. | ||||
|  * vcpu_get_reg and vcpu_set_reg should always be passed a register number | ||||
|  * coming from a read of ESR_EL2. Otherwise, it may give the wrong result on | ||||
|  * AArch32 with banked registers. | ||||
|  */ | ||||
| static inline unsigned long *vcpu_reg(const struct kvm_vcpu *vcpu, u8 reg_num) | ||||
| static inline unsigned long vcpu_get_reg(const struct kvm_vcpu *vcpu, | ||||
| 					 u8 reg_num) | ||||
| { | ||||
| 	return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.regs[reg_num]; | ||||
| 	return (reg_num == 31) ? 0 : vcpu_gp_regs(vcpu)->regs.regs[reg_num]; | ||||
| } | ||||
| 
 | ||||
| static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num, | ||||
| 				unsigned long val) | ||||
| { | ||||
| 	if (reg_num != 31) | ||||
| 		vcpu_gp_regs(vcpu)->regs.regs[reg_num] = val; | ||||
| } | ||||
| 
 | ||||
| /* Get vcpu SPSR for current mode */ | ||||
|  | ||||
| @ -37,7 +37,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||||
| { | ||||
| 	int ret; | ||||
| 
 | ||||
| 	trace_kvm_hvc_arm64(*vcpu_pc(vcpu), *vcpu_reg(vcpu, 0), | ||||
| 	trace_kvm_hvc_arm64(*vcpu_pc(vcpu), vcpu_get_reg(vcpu, 0), | ||||
| 			    kvm_vcpu_hvc_get_imm(vcpu)); | ||||
| 
 | ||||
| 	ret = kvm_psci_call(vcpu); | ||||
|  | ||||
| @ -78,7 +78,7 @@ static u32 get_ccsidr(u32 csselr) | ||||
|  * See note at ARMv7 ARM B1.14.4 (TL;DR: S/W ops are not easily virtualized). | ||||
|  */ | ||||
| static bool access_dcsw(struct kvm_vcpu *vcpu, | ||||
| 			const struct sys_reg_params *p, | ||||
| 			struct sys_reg_params *p, | ||||
| 			const struct sys_reg_desc *r) | ||||
| { | ||||
| 	if (!p->is_write) | ||||
| @ -94,21 +94,19 @@ static bool access_dcsw(struct kvm_vcpu *vcpu, | ||||
|  * sys_regs and leave it in complete control of the caches. | ||||
|  */ | ||||
| static bool access_vm_reg(struct kvm_vcpu *vcpu, | ||||
| 			  const struct sys_reg_params *p, | ||||
| 			  struct sys_reg_params *p, | ||||
| 			  const struct sys_reg_desc *r) | ||||
| { | ||||
| 	unsigned long val; | ||||
| 	bool was_enabled = vcpu_has_cache_enabled(vcpu); | ||||
| 
 | ||||
| 	BUG_ON(!p->is_write); | ||||
| 
 | ||||
| 	val = *vcpu_reg(vcpu, p->Rt); | ||||
| 	if (!p->is_aarch32) { | ||||
| 		vcpu_sys_reg(vcpu, r->reg) = val; | ||||
| 		vcpu_sys_reg(vcpu, r->reg) = p->regval; | ||||
| 	} else { | ||||
| 		if (!p->is_32bit) | ||||
| 			vcpu_cp15_64_high(vcpu, r->reg) = val >> 32; | ||||
| 		vcpu_cp15_64_low(vcpu, r->reg) = val & 0xffffffffUL; | ||||
| 			vcpu_cp15_64_high(vcpu, r->reg) = upper_32_bits(p->regval); | ||||
| 		vcpu_cp15_64_low(vcpu, r->reg) = lower_32_bits(p->regval); | ||||
| 	} | ||||
| 
 | ||||
| 	kvm_toggle_cache(vcpu, was_enabled); | ||||
| @ -122,22 +120,19 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu, | ||||
|  * for both AArch64 and AArch32 accesses. | ||||
|  */ | ||||
| static bool access_gic_sgi(struct kvm_vcpu *vcpu, | ||||
| 			   const struct sys_reg_params *p, | ||||
| 			   struct sys_reg_params *p, | ||||
| 			   const struct sys_reg_desc *r) | ||||
| { | ||||
| 	u64 val; | ||||
| 
 | ||||
| 	if (!p->is_write) | ||||
| 		return read_from_write_only(vcpu, p); | ||||
| 
 | ||||
| 	val = *vcpu_reg(vcpu, p->Rt); | ||||
| 	vgic_v3_dispatch_sgi(vcpu, val); | ||||
| 	vgic_v3_dispatch_sgi(vcpu, p->regval); | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static bool trap_raz_wi(struct kvm_vcpu *vcpu, | ||||
| 			const struct sys_reg_params *p, | ||||
| 			struct sys_reg_params *p, | ||||
| 			const struct sys_reg_desc *r) | ||||
| { | ||||
| 	if (p->is_write) | ||||
| @ -147,19 +142,19 @@ static bool trap_raz_wi(struct kvm_vcpu *vcpu, | ||||
| } | ||||
| 
 | ||||
| static bool trap_oslsr_el1(struct kvm_vcpu *vcpu, | ||||
| 			   const struct sys_reg_params *p, | ||||
| 			   struct sys_reg_params *p, | ||||
| 			   const struct sys_reg_desc *r) | ||||
| { | ||||
| 	if (p->is_write) { | ||||
| 		return ignore_write(vcpu, p); | ||||
| 	} else { | ||||
| 		*vcpu_reg(vcpu, p->Rt) = (1 << 3); | ||||
| 		p->regval = (1 << 3); | ||||
| 		return true; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static bool trap_dbgauthstatus_el1(struct kvm_vcpu *vcpu, | ||||
| 				   const struct sys_reg_params *p, | ||||
| 				   struct sys_reg_params *p, | ||||
| 				   const struct sys_reg_desc *r) | ||||
| { | ||||
| 	if (p->is_write) { | ||||
| @ -167,7 +162,7 @@ static bool trap_dbgauthstatus_el1(struct kvm_vcpu *vcpu, | ||||
| 	} else { | ||||
| 		u32 val; | ||||
| 		asm volatile("mrs %0, dbgauthstatus_el1" : "=r" (val)); | ||||
| 		*vcpu_reg(vcpu, p->Rt) = val; | ||||
| 		p->regval = val; | ||||
| 		return true; | ||||
| 	} | ||||
| } | ||||
| @ -200,17 +195,17 @@ static bool trap_dbgauthstatus_el1(struct kvm_vcpu *vcpu, | ||||
|  *   now use the debug registers. | ||||
|  */ | ||||
| static bool trap_debug_regs(struct kvm_vcpu *vcpu, | ||||
| 			    const struct sys_reg_params *p, | ||||
| 			    struct sys_reg_params *p, | ||||
| 			    const struct sys_reg_desc *r) | ||||
| { | ||||
| 	if (p->is_write) { | ||||
| 		vcpu_sys_reg(vcpu, r->reg) = *vcpu_reg(vcpu, p->Rt); | ||||
| 		vcpu_sys_reg(vcpu, r->reg) = p->regval; | ||||
| 		vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; | ||||
| 	} else { | ||||
| 		*vcpu_reg(vcpu, p->Rt) = vcpu_sys_reg(vcpu, r->reg); | ||||
| 		p->regval = vcpu_sys_reg(vcpu, r->reg); | ||||
| 	} | ||||
| 
 | ||||
| 	trace_trap_reg(__func__, r->reg, p->is_write, *vcpu_reg(vcpu, p->Rt)); | ||||
| 	trace_trap_reg(__func__, r->reg, p->is_write, p->regval); | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| @ -225,10 +220,10 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu, | ||||
|  * hyp.S code switches between host and guest values in future. | ||||
|  */ | ||||
| static inline void reg_to_dbg(struct kvm_vcpu *vcpu, | ||||
| 			      const struct sys_reg_params *p, | ||||
| 			      struct sys_reg_params *p, | ||||
| 			      u64 *dbg_reg) | ||||
| { | ||||
| 	u64 val = *vcpu_reg(vcpu, p->Rt); | ||||
| 	u64 val = p->regval; | ||||
| 
 | ||||
| 	if (p->is_32bit) { | ||||
| 		val &= 0xffffffffUL; | ||||
| @ -240,19 +235,16 @@ static inline void reg_to_dbg(struct kvm_vcpu *vcpu, | ||||
| } | ||||
| 
 | ||||
| static inline void dbg_to_reg(struct kvm_vcpu *vcpu, | ||||
| 			      const struct sys_reg_params *p, | ||||
| 			      struct sys_reg_params *p, | ||||
| 			      u64 *dbg_reg) | ||||
| { | ||||
| 	u64 val = *dbg_reg; | ||||
| 
 | ||||
| 	p->regval = *dbg_reg; | ||||
| 	if (p->is_32bit) | ||||
| 		val &= 0xffffffffUL; | ||||
| 
 | ||||
| 	*vcpu_reg(vcpu, p->Rt) = val; | ||||
| 		p->regval &= 0xffffffffUL; | ||||
| } | ||||
| 
 | ||||
| static inline bool trap_bvr(struct kvm_vcpu *vcpu, | ||||
| 			    const struct sys_reg_params *p, | ||||
| 			    struct sys_reg_params *p, | ||||
| 			    const struct sys_reg_desc *rd) | ||||
| { | ||||
| 	u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg]; | ||||
| @ -294,7 +286,7 @@ static inline void reset_bvr(struct kvm_vcpu *vcpu, | ||||
| } | ||||
| 
 | ||||
| static inline bool trap_bcr(struct kvm_vcpu *vcpu, | ||||
| 			    const struct sys_reg_params *p, | ||||
| 			    struct sys_reg_params *p, | ||||
| 			    const struct sys_reg_desc *rd) | ||||
| { | ||||
| 	u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bcr[rd->reg]; | ||||
| @ -337,7 +329,7 @@ static inline void reset_bcr(struct kvm_vcpu *vcpu, | ||||
| } | ||||
| 
 | ||||
| static inline bool trap_wvr(struct kvm_vcpu *vcpu, | ||||
| 			    const struct sys_reg_params *p, | ||||
| 			    struct sys_reg_params *p, | ||||
| 			    const struct sys_reg_desc *rd) | ||||
| { | ||||
| 	u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg]; | ||||
| @ -380,7 +372,7 @@ static inline void reset_wvr(struct kvm_vcpu *vcpu, | ||||
| } | ||||
| 
 | ||||
| static inline bool trap_wcr(struct kvm_vcpu *vcpu, | ||||
| 			    const struct sys_reg_params *p, | ||||
| 			    struct sys_reg_params *p, | ||||
| 			    const struct sys_reg_desc *rd) | ||||
| { | ||||
| 	u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_wcr[rd->reg]; | ||||
| @ -687,7 +679,7 @@ static const struct sys_reg_desc sys_reg_descs[] = { | ||||
| }; | ||||
| 
 | ||||
| static bool trap_dbgidr(struct kvm_vcpu *vcpu, | ||||
| 			const struct sys_reg_params *p, | ||||
| 			struct sys_reg_params *p, | ||||
| 			const struct sys_reg_desc *r) | ||||
| { | ||||
| 	if (p->is_write) { | ||||
| @ -697,23 +689,23 @@ static bool trap_dbgidr(struct kvm_vcpu *vcpu, | ||||
| 		u64 pfr = read_system_reg(SYS_ID_AA64PFR0_EL1); | ||||
| 		u32 el3 = !!cpuid_feature_extract_field(pfr, ID_AA64PFR0_EL3_SHIFT); | ||||
| 
 | ||||
| 		*vcpu_reg(vcpu, p->Rt) = ((((dfr >> ID_AA64DFR0_WRPS_SHIFT) & 0xf) << 28) | | ||||
| 					  (((dfr >> ID_AA64DFR0_BRPS_SHIFT) & 0xf) << 24) | | ||||
| 					  (((dfr >> ID_AA64DFR0_CTX_CMPS_SHIFT) & 0xf) << 20) | | ||||
| 					  (6 << 16) | (el3 << 14) | (el3 << 12)); | ||||
| 		p->regval = ((((dfr >> ID_AA64DFR0_WRPS_SHIFT) & 0xf) << 28) | | ||||
| 			     (((dfr >> ID_AA64DFR0_BRPS_SHIFT) & 0xf) << 24) | | ||||
| 			     (((dfr >> ID_AA64DFR0_CTX_CMPS_SHIFT) & 0xf) << 20) | ||||
| 			     | (6 << 16) | (el3 << 14) | (el3 << 12)); | ||||
| 		return true; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static bool trap_debug32(struct kvm_vcpu *vcpu, | ||||
| 			 const struct sys_reg_params *p, | ||||
| 			 struct sys_reg_params *p, | ||||
| 			 const struct sys_reg_desc *r) | ||||
| { | ||||
| 	if (p->is_write) { | ||||
| 		vcpu_cp14(vcpu, r->reg) = *vcpu_reg(vcpu, p->Rt); | ||||
| 		vcpu_cp14(vcpu, r->reg) = p->regval; | ||||
| 		vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; | ||||
| 	} else { | ||||
| 		*vcpu_reg(vcpu, p->Rt) = vcpu_cp14(vcpu, r->reg); | ||||
| 		p->regval = vcpu_cp14(vcpu, r->reg); | ||||
| 	} | ||||
| 
 | ||||
| 	return true; | ||||
| @ -731,7 +723,7 @@ static bool trap_debug32(struct kvm_vcpu *vcpu, | ||||
|  */ | ||||
| 
 | ||||
| static inline bool trap_xvr(struct kvm_vcpu *vcpu, | ||||
| 			    const struct sys_reg_params *p, | ||||
| 			    struct sys_reg_params *p, | ||||
| 			    const struct sys_reg_desc *rd) | ||||
| { | ||||
| 	u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg]; | ||||
| @ -740,12 +732,12 @@ static inline bool trap_xvr(struct kvm_vcpu *vcpu, | ||||
| 		u64 val = *dbg_reg; | ||||
| 
 | ||||
| 		val &= 0xffffffffUL; | ||||
| 		val |= *vcpu_reg(vcpu, p->Rt) << 32; | ||||
| 		val |= p->regval << 32; | ||||
| 		*dbg_reg = val; | ||||
| 
 | ||||
| 		vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; | ||||
| 	} else { | ||||
| 		*vcpu_reg(vcpu, p->Rt) = *dbg_reg >> 32; | ||||
| 		p->regval = *dbg_reg >> 32; | ||||
| 	} | ||||
| 
 | ||||
| 	trace_trap_reg(__func__, rd->reg, p->is_write, *dbg_reg); | ||||
| @ -991,7 +983,7 @@ int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||||
|  * Return 0 if the access has been handled, and -1 if not. | ||||
|  */ | ||||
| static int emulate_cp(struct kvm_vcpu *vcpu, | ||||
| 		      const struct sys_reg_params *params, | ||||
| 		      struct sys_reg_params *params, | ||||
| 		      const struct sys_reg_desc *table, | ||||
| 		      size_t num) | ||||
| { | ||||
| @ -1062,12 +1054,12 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu, | ||||
| { | ||||
| 	struct sys_reg_params params; | ||||
| 	u32 hsr = kvm_vcpu_get_hsr(vcpu); | ||||
| 	int Rt = (hsr >> 5) & 0xf; | ||||
| 	int Rt2 = (hsr >> 10) & 0xf; | ||||
| 
 | ||||
| 	params.is_aarch32 = true; | ||||
| 	params.is_32bit = false; | ||||
| 	params.CRm = (hsr >> 1) & 0xf; | ||||
| 	params.Rt = (hsr >> 5) & 0xf; | ||||
| 	params.is_write = ((hsr & 1) == 0); | ||||
| 
 | ||||
| 	params.Op0 = 0; | ||||
| @ -1076,15 +1068,12 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu, | ||||
| 	params.CRn = 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Massive hack here. Store Rt2 in the top 32bits so we only | ||||
| 	 * have one register to deal with. As we use the same trap | ||||
| 	 * Make a 64-bit value out of Rt and Rt2. As we use the same trap | ||||
| 	 * backends between AArch32 and AArch64, we get away with it. | ||||
| 	 */ | ||||
| 	if (params.is_write) { | ||||
| 		u64 val = *vcpu_reg(vcpu, params.Rt); | ||||
| 		val &= 0xffffffff; | ||||
| 		val |= *vcpu_reg(vcpu, Rt2) << 32; | ||||
| 		*vcpu_reg(vcpu, params.Rt) = val; | ||||
| 		params.regval = vcpu_get_reg(vcpu, Rt) & 0xffffffff; | ||||
| 		params.regval |= vcpu_get_reg(vcpu, Rt2) << 32; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!emulate_cp(vcpu, ¶ms, target_specific, nr_specific)) | ||||
| @ -1095,11 +1084,10 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu, | ||||
| 	unhandled_cp_access(vcpu, ¶ms); | ||||
| 
 | ||||
| out: | ||||
| 	/* Do the opposite hack for the read side */ | ||||
| 	/* Split up the value between registers for the read side */ | ||||
| 	if (!params.is_write) { | ||||
| 		u64 val = *vcpu_reg(vcpu, params.Rt); | ||||
| 		val >>= 32; | ||||
| 		*vcpu_reg(vcpu, Rt2) = val; | ||||
| 		vcpu_set_reg(vcpu, Rt, lower_32_bits(params.regval)); | ||||
| 		vcpu_set_reg(vcpu, Rt2, upper_32_bits(params.regval)); | ||||
| 	} | ||||
| 
 | ||||
| 	return 1; | ||||
| @ -1118,21 +1106,24 @@ static int kvm_handle_cp_32(struct kvm_vcpu *vcpu, | ||||
| { | ||||
| 	struct sys_reg_params params; | ||||
| 	u32 hsr = kvm_vcpu_get_hsr(vcpu); | ||||
| 	int Rt  = (hsr >> 5) & 0xf; | ||||
| 
 | ||||
| 	params.is_aarch32 = true; | ||||
| 	params.is_32bit = true; | ||||
| 	params.CRm = (hsr >> 1) & 0xf; | ||||
| 	params.Rt  = (hsr >> 5) & 0xf; | ||||
| 	params.regval = vcpu_get_reg(vcpu, Rt); | ||||
| 	params.is_write = ((hsr & 1) == 0); | ||||
| 	params.CRn = (hsr >> 10) & 0xf; | ||||
| 	params.Op0 = 0; | ||||
| 	params.Op1 = (hsr >> 14) & 0x7; | ||||
| 	params.Op2 = (hsr >> 17) & 0x7; | ||||
| 
 | ||||
| 	if (!emulate_cp(vcpu, ¶ms, target_specific, nr_specific)) | ||||
| 		return 1; | ||||
| 	if (!emulate_cp(vcpu, ¶ms, global, nr_global)) | ||||
| 	if (!emulate_cp(vcpu, ¶ms, target_specific, nr_specific) || | ||||
| 	    !emulate_cp(vcpu, ¶ms, global, nr_global)) { | ||||
| 		if (!params.is_write) | ||||
| 			vcpu_set_reg(vcpu, Rt, params.regval); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	unhandled_cp_access(vcpu, ¶ms); | ||||
| 	return 1; | ||||
| @ -1175,7 +1166,7 @@ int kvm_handle_cp14_32(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||||
| } | ||||
| 
 | ||||
| static int emulate_sys_reg(struct kvm_vcpu *vcpu, | ||||
| 			   const struct sys_reg_params *params) | ||||
| 			   struct sys_reg_params *params) | ||||
| { | ||||
| 	size_t num; | ||||
| 	const struct sys_reg_desc *table, *r; | ||||
| @ -1230,6 +1221,8 @@ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||||
| { | ||||
| 	struct sys_reg_params params; | ||||
| 	unsigned long esr = kvm_vcpu_get_hsr(vcpu); | ||||
| 	int Rt = (esr >> 5) & 0x1f; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	trace_kvm_handle_sys_reg(esr); | ||||
| 
 | ||||
| @ -1240,10 +1233,14 @@ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||||
| 	params.CRn = (esr >> 10) & 0xf; | ||||
| 	params.CRm = (esr >> 1) & 0xf; | ||||
| 	params.Op2 = (esr >> 17) & 0x7; | ||||
| 	params.Rt = (esr >> 5) & 0x1f; | ||||
| 	params.regval = vcpu_get_reg(vcpu, Rt); | ||||
| 	params.is_write = !(esr & 1); | ||||
| 
 | ||||
| 	return emulate_sys_reg(vcpu, ¶ms); | ||||
| 	ret = emulate_sys_reg(vcpu, ¶ms); | ||||
| 
 | ||||
| 	if (!params.is_write) | ||||
| 		vcpu_set_reg(vcpu, Rt, params.regval); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /******************************************************************************
 | ||||
|  | ||||
| @ -28,7 +28,7 @@ struct sys_reg_params { | ||||
| 	u8	CRn; | ||||
| 	u8	CRm; | ||||
| 	u8	Op2; | ||||
| 	u8	Rt; | ||||
| 	u64	regval; | ||||
| 	bool	is_write; | ||||
| 	bool	is_aarch32; | ||||
| 	bool	is_32bit;	/* Only valid if is_aarch32 is true */ | ||||
| @ -44,7 +44,7 @@ struct sys_reg_desc { | ||||
| 
 | ||||
| 	/* Trapped access from guest, if non-NULL. */ | ||||
| 	bool (*access)(struct kvm_vcpu *, | ||||
| 		       const struct sys_reg_params *, | ||||
| 		       struct sys_reg_params *, | ||||
| 		       const struct sys_reg_desc *); | ||||
| 
 | ||||
| 	/* Initialization for vcpu. */ | ||||
| @ -77,9 +77,9 @@ static inline bool ignore_write(struct kvm_vcpu *vcpu, | ||||
| } | ||||
| 
 | ||||
| static inline bool read_zero(struct kvm_vcpu *vcpu, | ||||
| 			     const struct sys_reg_params *p) | ||||
| 			     struct sys_reg_params *p) | ||||
| { | ||||
| 	*vcpu_reg(vcpu, p->Rt) = 0; | ||||
| 	p->regval = 0; | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -31,13 +31,13 @@ | ||||
| #include "sys_regs.h" | ||||
| 
 | ||||
| static bool access_actlr(struct kvm_vcpu *vcpu, | ||||
| 			 const struct sys_reg_params *p, | ||||
| 			 struct sys_reg_params *p, | ||||
| 			 const struct sys_reg_desc *r) | ||||
| { | ||||
| 	if (p->is_write) | ||||
| 		return ignore_write(vcpu, p); | ||||
| 
 | ||||
| 	*vcpu_reg(vcpu, p->Rt) = vcpu_sys_reg(vcpu, ACTLR_EL1); | ||||
| 	p->regval = vcpu_sys_reg(vcpu, ACTLR_EL1); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -139,6 +139,12 @@ static inline int epilogue_offset(const struct jit_ctx *ctx) | ||||
| /* Stack must be multiples of 16B */ | ||||
| #define STACK_ALIGN(sz) (((sz) + 15) & ~15) | ||||
| 
 | ||||
| #define _STACK_SIZE \ | ||||
| 	(MAX_BPF_STACK \ | ||||
| 	 + 4 /* extra for skb_copy_bits buffer */) | ||||
| 
 | ||||
| #define STACK_SIZE STACK_ALIGN(_STACK_SIZE) | ||||
| 
 | ||||
| static void build_prologue(struct jit_ctx *ctx) | ||||
| { | ||||
| 	const u8 r6 = bpf2a64[BPF_REG_6]; | ||||
| @ -150,10 +156,6 @@ static void build_prologue(struct jit_ctx *ctx) | ||||
| 	const u8 rx = bpf2a64[BPF_REG_X]; | ||||
| 	const u8 tmp1 = bpf2a64[TMP_REG_1]; | ||||
| 	const u8 tmp2 = bpf2a64[TMP_REG_2]; | ||||
| 	int stack_size = MAX_BPF_STACK; | ||||
| 
 | ||||
| 	stack_size += 4; /* extra for skb_copy_bits buffer */ | ||||
| 	stack_size = STACK_ALIGN(stack_size); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * BPF prog stack layout | ||||
| @ -165,12 +167,13 @@ static void build_prologue(struct jit_ctx *ctx) | ||||
| 	 *                        | ... | callee saved registers | ||||
| 	 *                        +-----+ | ||||
| 	 *                        |     | x25/x26 | ||||
| 	 * BPF fp register => -80:+-----+ | ||||
| 	 * BPF fp register => -80:+-----+ <= (BPF_FP) | ||||
| 	 *                        |     | | ||||
| 	 *                        | ... | BPF prog stack | ||||
| 	 *                        |     | | ||||
| 	 *                        |     | | ||||
| 	 * current A64_SP =>      +-----+ | ||||
| 	 *                        +-----+ <= (BPF_FP - MAX_BPF_STACK) | ||||
| 	 *                        |RSVD | JIT scratchpad | ||||
| 	 * current A64_SP =>      +-----+ <= (BPF_FP - STACK_SIZE) | ||||
| 	 *                        |     | | ||||
| 	 *                        | ... | Function call stack | ||||
| 	 *                        |     | | ||||
| @ -196,7 +199,7 @@ static void build_prologue(struct jit_ctx *ctx) | ||||
| 	emit(A64_MOV(1, fp, A64_SP), ctx); | ||||
| 
 | ||||
| 	/* Set up function call stack */ | ||||
| 	emit(A64_SUB_I(1, A64_SP, A64_SP, stack_size), ctx); | ||||
| 	emit(A64_SUB_I(1, A64_SP, A64_SP, STACK_SIZE), ctx); | ||||
| 
 | ||||
| 	/* Clear registers A and X */ | ||||
| 	emit_a64_mov_i64(ra, 0, ctx); | ||||
| @ -213,13 +216,9 @@ static void build_epilogue(struct jit_ctx *ctx) | ||||
| 	const u8 fp = bpf2a64[BPF_REG_FP]; | ||||
| 	const u8 tmp1 = bpf2a64[TMP_REG_1]; | ||||
| 	const u8 tmp2 = bpf2a64[TMP_REG_2]; | ||||
| 	int stack_size = MAX_BPF_STACK; | ||||
| 
 | ||||
| 	stack_size += 4; /* extra for skb_copy_bits buffer */ | ||||
| 	stack_size = STACK_ALIGN(stack_size); | ||||
| 
 | ||||
| 	/* We're done with BPF stack */ | ||||
| 	emit(A64_ADD_I(1, A64_SP, A64_SP, stack_size), ctx); | ||||
| 	emit(A64_ADD_I(1, A64_SP, A64_SP, STACK_SIZE), ctx); | ||||
| 
 | ||||
| 	/* Restore fs (x25) and x26 */ | ||||
| 	emit(A64_POP(fp, A64_R(26), A64_SP), ctx); | ||||
| @ -591,7 +590,25 @@ emit_cond_jmp: | ||||
| 	case BPF_ST | BPF_MEM | BPF_H: | ||||
| 	case BPF_ST | BPF_MEM | BPF_B: | ||||
| 	case BPF_ST | BPF_MEM | BPF_DW: | ||||
| 		goto notyet; | ||||
| 		/* Load imm to a register then store it */ | ||||
| 		ctx->tmp_used = 1; | ||||
| 		emit_a64_mov_i(1, tmp2, off, ctx); | ||||
| 		emit_a64_mov_i(1, tmp, imm, ctx); | ||||
| 		switch (BPF_SIZE(code)) { | ||||
| 		case BPF_W: | ||||
| 			emit(A64_STR32(tmp, dst, tmp2), ctx); | ||||
| 			break; | ||||
| 		case BPF_H: | ||||
| 			emit(A64_STRH(tmp, dst, tmp2), ctx); | ||||
| 			break; | ||||
| 		case BPF_B: | ||||
| 			emit(A64_STRB(tmp, dst, tmp2), ctx); | ||||
| 			break; | ||||
| 		case BPF_DW: | ||||
| 			emit(A64_STR64(tmp, dst, tmp2), ctx); | ||||
| 			break; | ||||
| 		} | ||||
| 		break; | ||||
| 
 | ||||
| 	/* STX: *(size *)(dst + off) = src */ | ||||
| 	case BPF_STX | BPF_MEM | BPF_W: | ||||
| @ -658,7 +675,7 @@ emit_cond_jmp: | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 		emit_a64_mov_i64(r3, size, ctx); | ||||
| 		emit(A64_ADD_I(1, r4, fp, MAX_BPF_STACK), ctx); | ||||
| 		emit(A64_SUB_I(1, r4, fp, STACK_SIZE), ctx); | ||||
| 		emit_a64_mov_i64(r5, (unsigned long)bpf_load_pointer, ctx); | ||||
| 		emit(A64_PUSH(A64_FP, A64_LR, A64_SP), ctx); | ||||
| 		emit(A64_MOV(1, A64_FP, A64_SP), ctx); | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| config MN10300 | ||||
| 	def_bool y | ||||
| 	select HAVE_OPROFILE | ||||
| 	select HAVE_UID16 | ||||
| 	select GENERIC_IRQ_SHOW | ||||
| 	select ARCH_WANT_IPC_PARSE_VERSION | ||||
| 	select HAVE_ARCH_TRACEHOOK | ||||
| @ -37,9 +38,6 @@ config HIGHMEM | ||||
| config NUMA | ||||
| 	def_bool n | ||||
| 
 | ||||
| config UID16 | ||||
| 	def_bool y | ||||
| 
 | ||||
| config RWSEM_GENERIC_SPINLOCK | ||||
| 	def_bool y | ||||
| 
 | ||||
|  | ||||
| @ -23,7 +23,6 @@ | ||||
| #include <stdarg.h> | ||||
| #include <linux/types.h> | ||||
| #include <linux/edd.h> | ||||
| #include <asm/boot.h> | ||||
| #include <asm/setup.h> | ||||
| #include "bitops.h" | ||||
| #include "ctype.h" | ||||
|  | ||||
| @ -19,6 +19,8 @@ | ||||
| #include "video.h" | ||||
| #include "vesa.h" | ||||
| 
 | ||||
| #include <uapi/asm/boot.h> | ||||
| 
 | ||||
| /*
 | ||||
|  * Common variables | ||||
|  */ | ||||
|  | ||||
| @ -13,6 +13,8 @@ | ||||
|  * Select video mode | ||||
|  */ | ||||
| 
 | ||||
| #include <uapi/asm/boot.h> | ||||
| 
 | ||||
| #include "boot.h" | ||||
| #include "video.h" | ||||
| #include "vesa.h" | ||||
|  | ||||
| @ -509,6 +509,17 @@ END(irq_entries_start) | ||||
| 	 * tracking that we're in kernel mode. | ||||
| 	 */ | ||||
| 	SWAPGS | ||||
| 
 | ||||
| 	/* | ||||
| 	 * We need to tell lockdep that IRQs are off.  We can't do this until | ||||
| 	 * we fix gsbase, and we should do it before enter_from_user_mode | ||||
| 	 * (which can take locks).  Since TRACE_IRQS_OFF idempotent, | ||||
| 	 * the simplest way to handle it is to just call it twice if | ||||
| 	 * we enter from user mode.  There's no reason to optimize this since | ||||
| 	 * TRACE_IRQS_OFF is a no-op if lockdep is off. | ||||
| 	 */ | ||||
| 	TRACE_IRQS_OFF | ||||
| 
 | ||||
| #ifdef CONFIG_CONTEXT_TRACKING | ||||
| 	call enter_from_user_mode | ||||
| #endif | ||||
| @ -1049,12 +1060,18 @@ ENTRY(error_entry) | ||||
| 	SWAPGS | ||||
| 
 | ||||
| .Lerror_entry_from_usermode_after_swapgs: | ||||
| 	/* | ||||
| 	 * We need to tell lockdep that IRQs are off.  We can't do this until | ||||
| 	 * we fix gsbase, and we should do it before enter_from_user_mode | ||||
| 	 * (which can take locks). | ||||
| 	 */ | ||||
| 	TRACE_IRQS_OFF | ||||
| #ifdef CONFIG_CONTEXT_TRACKING | ||||
| 	call enter_from_user_mode | ||||
| #endif | ||||
| 	ret | ||||
| 
 | ||||
| .Lerror_entry_done: | ||||
| 
 | ||||
| 	TRACE_IRQS_OFF | ||||
| 	ret | ||||
| 
 | ||||
|  | ||||
| @ -9,20 +9,22 @@ | ||||
| #define PAGE_SIZE	(_AC(1,UL) << PAGE_SHIFT) | ||||
| #define PAGE_MASK	(~(PAGE_SIZE-1)) | ||||
| 
 | ||||
| #define __PHYSICAL_MASK		((phys_addr_t)((1ULL << __PHYSICAL_MASK_SHIFT) - 1)) | ||||
| #define __VIRTUAL_MASK		((1UL << __VIRTUAL_MASK_SHIFT) - 1) | ||||
| 
 | ||||
| /* Cast PAGE_MASK to a signed type so that it is sign-extended if
 | ||||
|    virtual addresses are 32-bits but physical addresses are larger | ||||
|    (ie, 32-bit PAE). */ | ||||
| #define PHYSICAL_PAGE_MASK	(((signed long)PAGE_MASK) & __PHYSICAL_MASK) | ||||
| 
 | ||||
| #define PMD_PAGE_SIZE		(_AC(1, UL) << PMD_SHIFT) | ||||
| #define PMD_PAGE_MASK		(~(PMD_PAGE_SIZE-1)) | ||||
| 
 | ||||
| #define PUD_PAGE_SIZE		(_AC(1, UL) << PUD_SHIFT) | ||||
| #define PUD_PAGE_MASK		(~(PUD_PAGE_SIZE-1)) | ||||
| 
 | ||||
| #define __PHYSICAL_MASK		((phys_addr_t)((1ULL << __PHYSICAL_MASK_SHIFT) - 1)) | ||||
| #define __VIRTUAL_MASK		((1UL << __VIRTUAL_MASK_SHIFT) - 1) | ||||
| 
 | ||||
| /* Cast *PAGE_MASK to a signed type so that it is sign-extended if
 | ||||
|    virtual addresses are 32-bits but physical addresses are larger | ||||
|    (ie, 32-bit PAE). */ | ||||
| #define PHYSICAL_PAGE_MASK	(((signed long)PAGE_MASK) & __PHYSICAL_MASK) | ||||
| #define PHYSICAL_PMD_PAGE_MASK	(((signed long)PMD_PAGE_MASK) & __PHYSICAL_MASK) | ||||
| #define PHYSICAL_PUD_PAGE_MASK	(((signed long)PUD_PAGE_MASK) & __PHYSICAL_MASK) | ||||
| 
 | ||||
| #define HPAGE_SHIFT		PMD_SHIFT | ||||
| #define HPAGE_SIZE		(_AC(1,UL) << HPAGE_SHIFT) | ||||
| #define HPAGE_MASK		(~(HPAGE_SIZE - 1)) | ||||
|  | ||||
| @ -279,17 +279,14 @@ static inline pmdval_t native_pmd_val(pmd_t pmd) | ||||
| static inline pudval_t pud_pfn_mask(pud_t pud) | ||||
| { | ||||
| 	if (native_pud_val(pud) & _PAGE_PSE) | ||||
| 		return PUD_PAGE_MASK & PHYSICAL_PAGE_MASK; | ||||
| 		return PHYSICAL_PUD_PAGE_MASK; | ||||
| 	else | ||||
| 		return PTE_PFN_MASK; | ||||
| } | ||||
| 
 | ||||
| static inline pudval_t pud_flags_mask(pud_t pud) | ||||
| { | ||||
| 	if (native_pud_val(pud) & _PAGE_PSE) | ||||
| 		return ~(PUD_PAGE_MASK & (pudval_t)PHYSICAL_PAGE_MASK); | ||||
| 	else | ||||
| 		return ~PTE_PFN_MASK; | ||||
| 	return ~pud_pfn_mask(pud); | ||||
| } | ||||
| 
 | ||||
| static inline pudval_t pud_flags(pud_t pud) | ||||
| @ -300,17 +297,14 @@ static inline pudval_t pud_flags(pud_t pud) | ||||
| static inline pmdval_t pmd_pfn_mask(pmd_t pmd) | ||||
| { | ||||
| 	if (native_pmd_val(pmd) & _PAGE_PSE) | ||||
| 		return PMD_PAGE_MASK & PHYSICAL_PAGE_MASK; | ||||
| 		return PHYSICAL_PMD_PAGE_MASK; | ||||
| 	else | ||||
| 		return PTE_PFN_MASK; | ||||
| } | ||||
| 
 | ||||
| static inline pmdval_t pmd_flags_mask(pmd_t pmd) | ||||
| { | ||||
| 	if (native_pmd_val(pmd) & _PAGE_PSE) | ||||
| 		return ~(PMD_PAGE_MASK & (pmdval_t)PHYSICAL_PAGE_MASK); | ||||
| 	else | ||||
| 		return ~PTE_PFN_MASK; | ||||
| 	return ~pmd_pfn_mask(pmd); | ||||
| } | ||||
| 
 | ||||
| static inline pmdval_t pmd_flags(pmd_t pmd) | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| #ifndef _ASM_X86_PLATFORM_H | ||||
| #define _ASM_X86_PLATFORM_H | ||||
| 
 | ||||
| #include <asm/pgtable_types.h> | ||||
| #include <asm/bootparam.h> | ||||
| 
 | ||||
| struct mpc_bus; | ||||
|  | ||||
| @ -698,3 +698,4 @@ int __init microcode_init(void) | ||||
| 	return error; | ||||
| 
 | ||||
| } | ||||
| late_initcall(microcode_init); | ||||
|  | ||||
| @ -4,10 +4,22 @@ | ||||
|  */ | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/ioport.h> | ||||
| 
 | ||||
| static int found(u64 start, u64 end, void *data) | ||||
| { | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| static __init int register_e820_pmem(void) | ||||
| { | ||||
| 	char *pmem = "Persistent Memory (legacy)"; | ||||
| 	struct platform_device *pdev; | ||||
| 	int rc; | ||||
| 
 | ||||
| 	rc = walk_iomem_res(pmem, IORESOURCE_MEM, 0, -1, NULL, found); | ||||
| 	if (rc <= 0) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * See drivers/nvdimm/e820.c for the implementation, this is | ||||
|  | ||||
| @ -1250,8 +1250,6 @@ void __init setup_arch(char **cmdline_p) | ||||
| 	if (efi_enabled(EFI_BOOT)) | ||||
| 		efi_apply_memmap_quirks(); | ||||
| #endif | ||||
| 
 | ||||
| 	microcode_init(); | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_X86_32 | ||||
|  | ||||
| @ -690,12 +690,15 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs) | ||||
| 	signal_setup_done(failed, ksig, stepping); | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_X86_32 | ||||
| #define NR_restart_syscall	__NR_restart_syscall | ||||
| #else /* !CONFIG_X86_32 */ | ||||
| #define NR_restart_syscall	\ | ||||
| 	test_thread_flag(TIF_IA32) ? __NR_ia32_restart_syscall : __NR_restart_syscall | ||||
| #endif /* CONFIG_X86_32 */ | ||||
| static inline unsigned long get_nr_restart_syscall(const struct pt_regs *regs) | ||||
| { | ||||
| #if defined(CONFIG_X86_32) || !defined(CONFIG_X86_64) | ||||
| 	return __NR_restart_syscall; | ||||
| #else /* !CONFIG_X86_32 && CONFIG_X86_64 */ | ||||
| 	return test_thread_flag(TIF_IA32) ? __NR_ia32_restart_syscall : | ||||
| 		__NR_restart_syscall | (regs->orig_ax & __X32_SYSCALL_BIT); | ||||
| #endif /* CONFIG_X86_32 || !CONFIG_X86_64 */ | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Note that 'init' is a special process: it doesn't get signals it doesn't | ||||
| @ -724,7 +727,7 @@ void do_signal(struct pt_regs *regs) | ||||
| 			break; | ||||
| 
 | ||||
| 		case -ERESTART_RESTARTBLOCK: | ||||
| 			regs->ax = NR_restart_syscall; | ||||
| 			regs->ax = get_nr_restart_syscall(regs); | ||||
| 			regs->ip -= 2; | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| @ -509,7 +509,7 @@ void __inquire_remote_apic(int apicid) | ||||
|  */ | ||||
| #define UDELAY_10MS_DEFAULT 10000 | ||||
| 
 | ||||
| static unsigned int init_udelay = INT_MAX; | ||||
| static unsigned int init_udelay = UINT_MAX; | ||||
| 
 | ||||
| static int __init cpu_init_udelay(char *str) | ||||
| { | ||||
| @ -522,14 +522,15 @@ early_param("cpu_init_udelay", cpu_init_udelay); | ||||
| static void __init smp_quirk_init_udelay(void) | ||||
| { | ||||
| 	/* if cmdline changed it from default, leave it alone */ | ||||
| 	if (init_udelay != INT_MAX) | ||||
| 	if (init_udelay != UINT_MAX) | ||||
| 		return; | ||||
| 
 | ||||
| 	/* if modern processor, use no delay */ | ||||
| 	if (((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && (boot_cpu_data.x86 == 6)) || | ||||
| 	    ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && (boot_cpu_data.x86 >= 0xF))) | ||||
| 	    ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && (boot_cpu_data.x86 >= 0xF))) { | ||||
| 		init_udelay = 0; | ||||
| 
 | ||||
| 		return; | ||||
| 	} | ||||
| 	/* else, use legacy delay */ | ||||
| 	init_udelay = UDELAY_10MS_DEFAULT; | ||||
| } | ||||
|  | ||||
| @ -101,19 +101,19 @@ static int get_reg_offset(struct insn *insn, struct pt_regs *regs, | ||||
| 	switch (type) { | ||||
| 	case REG_TYPE_RM: | ||||
| 		regno = X86_MODRM_RM(insn->modrm.value); | ||||
| 		if (X86_REX_B(insn->rex_prefix.value) == 1) | ||||
| 		if (X86_REX_B(insn->rex_prefix.value)) | ||||
| 			regno += 8; | ||||
| 		break; | ||||
| 
 | ||||
| 	case REG_TYPE_INDEX: | ||||
| 		regno = X86_SIB_INDEX(insn->sib.value); | ||||
| 		if (X86_REX_X(insn->rex_prefix.value) == 1) | ||||
| 		if (X86_REX_X(insn->rex_prefix.value)) | ||||
| 			regno += 8; | ||||
| 		break; | ||||
| 
 | ||||
| 	case REG_TYPE_BASE: | ||||
| 		regno = X86_SIB_BASE(insn->sib.value); | ||||
| 		if (X86_REX_B(insn->rex_prefix.value) == 1) | ||||
| 		if (X86_REX_B(insn->rex_prefix.value)) | ||||
| 			regno += 8; | ||||
| 		break; | ||||
| 
 | ||||
|  | ||||
| @ -50,18 +50,9 @@ void x86_pci_root_bus_resources(int bus, struct list_head *resources) | ||||
| 	if (!found) | ||||
| 		pci_add_resource(resources, &info->busn); | ||||
| 
 | ||||
| 	list_for_each_entry(root_res, &info->resources, list) { | ||||
| 		struct resource *res; | ||||
| 		struct resource *root; | ||||
| 	list_for_each_entry(root_res, &info->resources, list) | ||||
| 		pci_add_resource(resources, &root_res->res); | ||||
| 
 | ||||
| 		res = &root_res->res; | ||||
| 		pci_add_resource(resources, res); | ||||
| 		if (res->flags & IORESOURCE_IO) | ||||
| 			root = &ioport_resource; | ||||
| 		else | ||||
| 			root = &iomem_resource; | ||||
| 		insert_resource(root, res); | ||||
| 	} | ||||
| 	return; | ||||
| 
 | ||||
| default_resources: | ||||
|  | ||||
| @ -2114,7 +2114,8 @@ blk_qc_t submit_bio(int rw, struct bio *bio) | ||||
| EXPORT_SYMBOL(submit_bio); | ||||
| 
 | ||||
| /**
 | ||||
|  * blk_rq_check_limits - Helper function to check a request for the queue limit | ||||
|  * blk_cloned_rq_check_limits - Helper function to check a cloned request | ||||
|  *                              for new the queue limits | ||||
|  * @q:  the queue | ||||
|  * @rq: the request being checked | ||||
|  * | ||||
| @ -2125,20 +2126,13 @@ EXPORT_SYMBOL(submit_bio); | ||||
|  *    after it is inserted to @q, it should be checked against @q before | ||||
|  *    the insertion using this generic function. | ||||
|  * | ||||
|  *    This function should also be useful for request stacking drivers | ||||
|  *    in some cases below, so export this function. | ||||
|  *    Request stacking drivers like request-based dm may change the queue | ||||
|  *    limits while requests are in the queue (e.g. dm's table swapping). | ||||
|  *    Such request stacking drivers should check those requests against | ||||
|  *    the new queue limits again when they dispatch those requests, | ||||
|  *    although such checkings are also done against the old queue limits | ||||
|  *    when submitting requests. | ||||
|  *    limits when retrying requests on other queues. Those requests need | ||||
|  *    to be checked against the new queue limits again during dispatch. | ||||
|  */ | ||||
| int blk_rq_check_limits(struct request_queue *q, struct request *rq) | ||||
| static int blk_cloned_rq_check_limits(struct request_queue *q, | ||||
| 				      struct request *rq) | ||||
| { | ||||
| 	if (!rq_mergeable(rq)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (blk_rq_sectors(rq) > blk_queue_get_max_sectors(q, rq->cmd_flags)) { | ||||
| 		printk(KERN_ERR "%s: over max size limit.\n", __func__); | ||||
| 		return -EIO; | ||||
| @ -2158,7 +2152,6 @@ int blk_rq_check_limits(struct request_queue *q, struct request *rq) | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(blk_rq_check_limits); | ||||
| 
 | ||||
| /**
 | ||||
|  * blk_insert_cloned_request - Helper for stacking drivers to submit a request | ||||
| @ -2170,7 +2163,7 @@ int blk_insert_cloned_request(struct request_queue *q, struct request *rq) | ||||
| 	unsigned long flags; | ||||
| 	int where = ELEVATOR_INSERT_BACK; | ||||
| 
 | ||||
| 	if (blk_rq_check_limits(q, rq)) | ||||
| 	if (blk_cloned_rq_check_limits(q, rq)) | ||||
| 		return -EIO; | ||||
| 
 | ||||
| 	if (rq->rq_disk && | ||||
|  | ||||
| @ -103,6 +103,9 @@ static struct bio *blk_bio_segment_split(struct request_queue *q, | ||||
| 			bvprv = bv; | ||||
| 			bvprvp = &bvprv; | ||||
| 			sectors += bv.bv_len >> 9; | ||||
| 
 | ||||
| 			if (nsegs == 1 && seg_size > front_seg_size) | ||||
| 				front_seg_size = seg_size; | ||||
| 			continue; | ||||
| 		} | ||||
| new_segment: | ||||
|  | ||||
| @ -91,7 +91,8 @@ void blk_set_default_limits(struct queue_limits *lim) | ||||
| 	lim->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK; | ||||
| 	lim->virt_boundary_mask = 0; | ||||
| 	lim->max_segment_size = BLK_MAX_SEGMENT_SIZE; | ||||
| 	lim->max_sectors = lim->max_hw_sectors = BLK_SAFE_MAX_SECTORS; | ||||
| 	lim->max_sectors = lim->max_dev_sectors = lim->max_hw_sectors = | ||||
| 		BLK_SAFE_MAX_SECTORS; | ||||
| 	lim->chunk_sectors = 0; | ||||
| 	lim->max_write_same_sectors = 0; | ||||
| 	lim->max_discard_sectors = 0; | ||||
| @ -127,6 +128,7 @@ void blk_set_stacking_limits(struct queue_limits *lim) | ||||
| 	lim->max_hw_sectors = UINT_MAX; | ||||
| 	lim->max_segment_size = UINT_MAX; | ||||
| 	lim->max_sectors = UINT_MAX; | ||||
| 	lim->max_dev_sectors = UINT_MAX; | ||||
| 	lim->max_write_same_sectors = UINT_MAX; | ||||
| } | ||||
| EXPORT_SYMBOL(blk_set_stacking_limits); | ||||
| @ -214,8 +216,8 @@ void blk_queue_bounce_limit(struct request_queue *q, u64 max_addr) | ||||
| EXPORT_SYMBOL(blk_queue_bounce_limit); | ||||
| 
 | ||||
| /**
 | ||||
|  * blk_limits_max_hw_sectors - set hard and soft limit of max sectors for request | ||||
|  * @limits: the queue limits | ||||
|  * blk_queue_max_hw_sectors - set max sectors for a request for this queue | ||||
|  * @q:  the request queue for the device | ||||
|  * @max_hw_sectors:  max hardware sectors in the usual 512b unit | ||||
|  * | ||||
|  * Description: | ||||
| @ -224,13 +226,19 @@ EXPORT_SYMBOL(blk_queue_bounce_limit); | ||||
|  *    the device driver based upon the capabilities of the I/O | ||||
|  *    controller. | ||||
|  * | ||||
|  *    max_dev_sectors is a hard limit imposed by the storage device for | ||||
|  *    READ/WRITE requests. It is set by the disk driver. | ||||
|  * | ||||
|  *    max_sectors is a soft limit imposed by the block layer for | ||||
|  *    filesystem type requests.  This value can be overridden on a | ||||
|  *    per-device basis in /sys/block/<device>/queue/max_sectors_kb. | ||||
|  *    The soft limit can not exceed max_hw_sectors. | ||||
|  **/ | ||||
| void blk_limits_max_hw_sectors(struct queue_limits *limits, unsigned int max_hw_sectors) | ||||
| void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_sectors) | ||||
| { | ||||
| 	struct queue_limits *limits = &q->limits; | ||||
| 	unsigned int max_sectors; | ||||
| 
 | ||||
| 	if ((max_hw_sectors << 9) < PAGE_CACHE_SIZE) { | ||||
| 		max_hw_sectors = 1 << (PAGE_CACHE_SHIFT - 9); | ||||
| 		printk(KERN_INFO "%s: set to minimum %d\n", | ||||
| @ -238,22 +246,9 @@ void blk_limits_max_hw_sectors(struct queue_limits *limits, unsigned int max_hw_ | ||||
| 	} | ||||
| 
 | ||||
| 	limits->max_hw_sectors = max_hw_sectors; | ||||
| 	limits->max_sectors = min_t(unsigned int, max_hw_sectors, | ||||
| 				    BLK_DEF_MAX_SECTORS); | ||||
| } | ||||
| EXPORT_SYMBOL(blk_limits_max_hw_sectors); | ||||
| 
 | ||||
| /**
 | ||||
|  * blk_queue_max_hw_sectors - set max sectors for a request for this queue | ||||
|  * @q:  the request queue for the device | ||||
|  * @max_hw_sectors:  max hardware sectors in the usual 512b unit | ||||
|  * | ||||
|  * Description: | ||||
|  *    See description for blk_limits_max_hw_sectors(). | ||||
|  **/ | ||||
| void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_sectors) | ||||
| { | ||||
| 	blk_limits_max_hw_sectors(&q->limits, max_hw_sectors); | ||||
| 	max_sectors = min_not_zero(max_hw_sectors, limits->max_dev_sectors); | ||||
| 	max_sectors = min_t(unsigned int, max_sectors, BLK_DEF_MAX_SECTORS); | ||||
| 	limits->max_sectors = max_sectors; | ||||
| } | ||||
| EXPORT_SYMBOL(blk_queue_max_hw_sectors); | ||||
| 
 | ||||
| @ -527,6 +522,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, | ||||
| 
 | ||||
| 	t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors); | ||||
| 	t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors); | ||||
| 	t->max_dev_sectors = min_not_zero(t->max_dev_sectors, b->max_dev_sectors); | ||||
| 	t->max_write_same_sectors = min(t->max_write_same_sectors, | ||||
| 					b->max_write_same_sectors); | ||||
| 	t->bounce_pfn = min_not_zero(t->bounce_pfn, b->bounce_pfn); | ||||
|  | ||||
| @ -205,6 +205,9 @@ queue_max_sectors_store(struct request_queue *q, const char *page, size_t count) | ||||
| 	if (ret < 0) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	max_hw_sectors_kb = min_not_zero(max_hw_sectors_kb, (unsigned long) | ||||
| 					 q->limits.max_dev_sectors >> 1); | ||||
| 
 | ||||
| 	if (max_sectors_kb > max_hw_sectors_kb || max_sectors_kb < page_kb) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
|  | ||||
| @ -397,7 +397,7 @@ static int drop_partitions(struct gendisk *disk, struct block_device *bdev) | ||||
| 	struct hd_struct *part; | ||||
| 	int res; | ||||
| 
 | ||||
| 	if (bdev->bd_part_count) | ||||
| 	if (bdev->bd_part_count || bdev->bd_super) | ||||
| 		return -EBUSY; | ||||
| 	res = invalidate_partition(disk, 0); | ||||
| 	if (res) | ||||
|  | ||||
| @ -125,7 +125,7 @@ static int aead_wait_for_data(struct sock *sk, unsigned flags) | ||||
| 	if (flags & MSG_DONTWAIT) | ||||
| 		return -EAGAIN; | ||||
| 
 | ||||
| 	set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); | ||||
| 	sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); | ||||
| 
 | ||||
| 	for (;;) { | ||||
| 		if (signal_pending(current)) | ||||
| @ -139,7 +139,7 @@ static int aead_wait_for_data(struct sock *sk, unsigned flags) | ||||
| 	} | ||||
| 	finish_wait(sk_sleep(sk), &wait); | ||||
| 
 | ||||
| 	clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); | ||||
| 	sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk); | ||||
| 
 | ||||
| 	return err; | ||||
| } | ||||
|  | ||||
| @ -212,7 +212,7 @@ static int skcipher_wait_for_wmem(struct sock *sk, unsigned flags) | ||||
| 	if (flags & MSG_DONTWAIT) | ||||
| 		return -EAGAIN; | ||||
| 
 | ||||
| 	set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); | ||||
| 	sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); | ||||
| 
 | ||||
| 	for (;;) { | ||||
| 		if (signal_pending(current)) | ||||
| @ -258,7 +258,7 @@ static int skcipher_wait_for_data(struct sock *sk, unsigned flags) | ||||
| 		return -EAGAIN; | ||||
| 	} | ||||
| 
 | ||||
| 	set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); | ||||
| 	sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); | ||||
| 
 | ||||
| 	for (;;) { | ||||
| 		if (signal_pending(current)) | ||||
| @ -272,7 +272,7 @@ static int skcipher_wait_for_data(struct sock *sk, unsigned flags) | ||||
| 	} | ||||
| 	finish_wait(sk_sleep(sk), &wait); | ||||
| 
 | ||||
| 	clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); | ||||
| 	sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk); | ||||
| 
 | ||||
| 	return err; | ||||
| } | ||||
|  | ||||
| @ -58,10 +58,10 @@ config ACPI_CCA_REQUIRED | ||||
| 	bool | ||||
| 
 | ||||
| config ACPI_DEBUGGER | ||||
| 	bool "In-kernel debugger (EXPERIMENTAL)" | ||||
| 	bool "AML debugger interface (EXPERIMENTAL)" | ||||
| 	select ACPI_DEBUG | ||||
| 	help | ||||
| 	  Enable in-kernel debugging facilities: statistics, internal | ||||
| 	  Enable in-kernel debugging of AML facilities: statistics, internal | ||||
| 	  object dump, single step control method execution. | ||||
| 	  This is still under development, currently enabling this only | ||||
| 	  results in the compilation of the ACPICA debugger files. | ||||
|  | ||||
| @ -233,11 +233,12 @@ static bool add_spa(struct acpi_nfit_desc *acpi_desc, | ||||
| 		struct nfit_table_prev *prev, | ||||
| 		struct acpi_nfit_system_address *spa) | ||||
| { | ||||
| 	size_t length = min_t(size_t, sizeof(*spa), spa->header.length); | ||||
| 	struct device *dev = acpi_desc->dev; | ||||
| 	struct nfit_spa *nfit_spa; | ||||
| 
 | ||||
| 	list_for_each_entry(nfit_spa, &prev->spas, list) { | ||||
| 		if (memcmp(nfit_spa->spa, spa, sizeof(*spa)) == 0) { | ||||
| 		if (memcmp(nfit_spa->spa, spa, length) == 0) { | ||||
| 			list_move_tail(&nfit_spa->list, &acpi_desc->spas); | ||||
| 			return true; | ||||
| 		} | ||||
| @ -259,11 +260,12 @@ static bool add_memdev(struct acpi_nfit_desc *acpi_desc, | ||||
| 		struct nfit_table_prev *prev, | ||||
| 		struct acpi_nfit_memory_map *memdev) | ||||
| { | ||||
| 	size_t length = min_t(size_t, sizeof(*memdev), memdev->header.length); | ||||
| 	struct device *dev = acpi_desc->dev; | ||||
| 	struct nfit_memdev *nfit_memdev; | ||||
| 
 | ||||
| 	list_for_each_entry(nfit_memdev, &prev->memdevs, list) | ||||
| 		if (memcmp(nfit_memdev->memdev, memdev, sizeof(*memdev)) == 0) { | ||||
| 		if (memcmp(nfit_memdev->memdev, memdev, length) == 0) { | ||||
| 			list_move_tail(&nfit_memdev->list, &acpi_desc->memdevs); | ||||
| 			return true; | ||||
| 		} | ||||
| @ -284,11 +286,12 @@ static bool add_dcr(struct acpi_nfit_desc *acpi_desc, | ||||
| 		struct nfit_table_prev *prev, | ||||
| 		struct acpi_nfit_control_region *dcr) | ||||
| { | ||||
| 	size_t length = min_t(size_t, sizeof(*dcr), dcr->header.length); | ||||
| 	struct device *dev = acpi_desc->dev; | ||||
| 	struct nfit_dcr *nfit_dcr; | ||||
| 
 | ||||
| 	list_for_each_entry(nfit_dcr, &prev->dcrs, list) | ||||
| 		if (memcmp(nfit_dcr->dcr, dcr, sizeof(*dcr)) == 0) { | ||||
| 		if (memcmp(nfit_dcr->dcr, dcr, length) == 0) { | ||||
| 			list_move_tail(&nfit_dcr->list, &acpi_desc->dcrs); | ||||
| 			return true; | ||||
| 		} | ||||
| @ -308,11 +311,12 @@ static bool add_bdw(struct acpi_nfit_desc *acpi_desc, | ||||
| 		struct nfit_table_prev *prev, | ||||
| 		struct acpi_nfit_data_region *bdw) | ||||
| { | ||||
| 	size_t length = min_t(size_t, sizeof(*bdw), bdw->header.length); | ||||
| 	struct device *dev = acpi_desc->dev; | ||||
| 	struct nfit_bdw *nfit_bdw; | ||||
| 
 | ||||
| 	list_for_each_entry(nfit_bdw, &prev->bdws, list) | ||||
| 		if (memcmp(nfit_bdw->bdw, bdw, sizeof(*bdw)) == 0) { | ||||
| 		if (memcmp(nfit_bdw->bdw, bdw, length) == 0) { | ||||
| 			list_move_tail(&nfit_bdw->list, &acpi_desc->bdws); | ||||
| 			return true; | ||||
| 		} | ||||
| @ -332,11 +336,12 @@ static bool add_idt(struct acpi_nfit_desc *acpi_desc, | ||||
| 		struct nfit_table_prev *prev, | ||||
| 		struct acpi_nfit_interleave *idt) | ||||
| { | ||||
| 	size_t length = min_t(size_t, sizeof(*idt), idt->header.length); | ||||
| 	struct device *dev = acpi_desc->dev; | ||||
| 	struct nfit_idt *nfit_idt; | ||||
| 
 | ||||
| 	list_for_each_entry(nfit_idt, &prev->idts, list) | ||||
| 		if (memcmp(nfit_idt->idt, idt, sizeof(*idt)) == 0) { | ||||
| 		if (memcmp(nfit_idt->idt, idt, length) == 0) { | ||||
| 			list_move_tail(&nfit_idt->list, &acpi_desc->idts); | ||||
| 			return true; | ||||
| 		} | ||||
| @ -356,11 +361,12 @@ static bool add_flush(struct acpi_nfit_desc *acpi_desc, | ||||
| 		struct nfit_table_prev *prev, | ||||
| 		struct acpi_nfit_flush_address *flush) | ||||
| { | ||||
| 	size_t length = min_t(size_t, sizeof(*flush), flush->header.length); | ||||
| 	struct device *dev = acpi_desc->dev; | ||||
| 	struct nfit_flush *nfit_flush; | ||||
| 
 | ||||
| 	list_for_each_entry(nfit_flush, &prev->flushes, list) | ||||
| 		if (memcmp(nfit_flush->flush, flush, sizeof(*flush)) == 0) { | ||||
| 		if (memcmp(nfit_flush->flush, flush, length) == 0) { | ||||
| 			list_move_tail(&nfit_flush->list, &acpi_desc->flushes); | ||||
| 			return true; | ||||
| 		} | ||||
| @ -655,7 +661,7 @@ static ssize_t revision_show(struct device *dev, | ||||
| 	struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus); | ||||
| 	struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); | ||||
| 
 | ||||
| 	return sprintf(buf, "%d\n", acpi_desc->nfit->header.revision); | ||||
| 	return sprintf(buf, "%d\n", acpi_desc->acpi_header.revision); | ||||
| } | ||||
| static DEVICE_ATTR_RO(revision); | ||||
| 
 | ||||
| @ -1652,7 +1658,6 @@ int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz) | ||||
| 
 | ||||
| 	data = (u8 *) acpi_desc->nfit; | ||||
| 	end = data + sz; | ||||
| 	data += sizeof(struct acpi_table_nfit); | ||||
| 	while (!IS_ERR_OR_NULL(data)) | ||||
| 		data = add_table(acpi_desc, &prev, data, end); | ||||
| 
 | ||||
| @ -1748,13 +1753,29 @@ static int acpi_nfit_add(struct acpi_device *adev) | ||||
| 		return PTR_ERR(acpi_desc); | ||||
| 	} | ||||
| 
 | ||||
| 	acpi_desc->nfit = (struct acpi_table_nfit *) tbl; | ||||
| 	/*
 | ||||
| 	 * Save the acpi header for later and then skip it, | ||||
| 	 * making nfit point to the first nfit table header. | ||||
| 	 */ | ||||
| 	acpi_desc->acpi_header = *tbl; | ||||
| 	acpi_desc->nfit = (void *) tbl + sizeof(struct acpi_table_nfit); | ||||
| 	sz -= sizeof(struct acpi_table_nfit); | ||||
| 
 | ||||
| 	/* Evaluate _FIT and override with that if present */ | ||||
| 	status = acpi_evaluate_object(adev->handle, "_FIT", NULL, &buf); | ||||
| 	if (ACPI_SUCCESS(status) && buf.length > 0) { | ||||
| 		acpi_desc->nfit = (struct acpi_table_nfit *)buf.pointer; | ||||
| 		sz = buf.length; | ||||
| 		union acpi_object *obj; | ||||
| 		/*
 | ||||
| 		 * Adjust for the acpi_object header of the _FIT | ||||
| 		 */ | ||||
| 		obj = buf.pointer; | ||||
| 		if (obj->type == ACPI_TYPE_BUFFER) { | ||||
| 			acpi_desc->nfit = | ||||
| 				(struct acpi_nfit_header *)obj->buffer.pointer; | ||||
| 			sz = obj->buffer.length; | ||||
| 		} else | ||||
| 			dev_dbg(dev, "%s invalid type %d, ignoring _FIT\n", | ||||
| 				 __func__, (int) obj->type); | ||||
| 	} | ||||
| 
 | ||||
| 	rc = acpi_nfit_init(acpi_desc, sz); | ||||
| @ -1777,7 +1798,8 @@ static void acpi_nfit_notify(struct acpi_device *adev, u32 event) | ||||
| { | ||||
| 	struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(&adev->dev); | ||||
| 	struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; | ||||
| 	struct acpi_table_nfit *nfit_saved; | ||||
| 	struct acpi_nfit_header *nfit_saved; | ||||
| 	union acpi_object *obj; | ||||
| 	struct device *dev = &adev->dev; | ||||
| 	acpi_status status; | ||||
| 	int ret; | ||||
| @ -1808,12 +1830,19 @@ static void acpi_nfit_notify(struct acpi_device *adev, u32 event) | ||||
| 	} | ||||
| 
 | ||||
| 	nfit_saved = acpi_desc->nfit; | ||||
| 	acpi_desc->nfit = (struct acpi_table_nfit *)buf.pointer; | ||||
| 	ret = acpi_nfit_init(acpi_desc, buf.length); | ||||
| 	if (!ret) { | ||||
| 		/* Merge failed, restore old nfit, and exit */ | ||||
| 		acpi_desc->nfit = nfit_saved; | ||||
| 		dev_err(dev, "failed to merge updated NFIT\n"); | ||||
| 	obj = buf.pointer; | ||||
| 	if (obj->type == ACPI_TYPE_BUFFER) { | ||||
| 		acpi_desc->nfit = | ||||
| 			(struct acpi_nfit_header *)obj->buffer.pointer; | ||||
| 		ret = acpi_nfit_init(acpi_desc, obj->buffer.length); | ||||
| 		if (ret) { | ||||
| 			/* Merge failed, restore old nfit, and exit */ | ||||
| 			acpi_desc->nfit = nfit_saved; | ||||
| 			dev_err(dev, "failed to merge updated NFIT\n"); | ||||
| 		} | ||||
| 	} else { | ||||
| 		/* Bad _FIT, restore old nfit */ | ||||
| 		dev_err(dev, "Invalid _FIT\n"); | ||||
| 	} | ||||
| 	kfree(buf.pointer); | ||||
| 
 | ||||
|  | ||||
| @ -96,7 +96,8 @@ struct nfit_mem { | ||||
| 
 | ||||
| struct acpi_nfit_desc { | ||||
| 	struct nvdimm_bus_descriptor nd_desc; | ||||
| 	struct acpi_table_nfit *nfit; | ||||
| 	struct acpi_table_header acpi_header; | ||||
| 	struct acpi_nfit_header *nfit; | ||||
| 	struct mutex spa_map_mutex; | ||||
| 	struct mutex init_mutex; | ||||
| 	struct list_head spa_maps; | ||||
|  | ||||
| @ -768,6 +768,13 @@ static void pci_acpi_root_add_resources(struct acpi_pci_root_info *info) | ||||
| 		else | ||||
| 			continue; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * Some legacy x86 host bridge drivers use iomem_resource and | ||||
| 		 * ioport_resource as default resource pool, skip it. | ||||
| 		 */ | ||||
| 		if (res == root) | ||||
| 			continue; | ||||
| 
 | ||||
| 		conflict = insert_resource_conflict(root, res); | ||||
| 		if (conflict) { | ||||
| 			dev_info(&info->bridge->dev, | ||||
|  | ||||
| @ -1775,10 +1775,10 @@ int genpd_dev_pm_attach(struct device *dev) | ||||
| 	} | ||||
| 
 | ||||
| 	pd = of_genpd_get_from_provider(&pd_args); | ||||
| 	of_node_put(pd_args.np); | ||||
| 	if (IS_ERR(pd)) { | ||||
| 		dev_dbg(dev, "%s() failed to find PM domain: %ld\n", | ||||
| 			__func__, PTR_ERR(pd)); | ||||
| 		of_node_put(dev->of_node); | ||||
| 		return -EPROBE_DEFER; | ||||
| 	} | ||||
| 
 | ||||
| @ -1796,7 +1796,6 @@ int genpd_dev_pm_attach(struct device *dev) | ||||
| 	if (ret < 0) { | ||||
| 		dev_err(dev, "failed to add to PM domain %s: %d", | ||||
| 			pd->name, ret); | ||||
| 		of_node_put(dev->of_node); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -160,9 +160,6 @@ static bool default_power_down_ok(struct dev_pm_domain *pd) | ||||
| 		struct gpd_timing_data *td; | ||||
| 		s64 constraint_ns; | ||||
| 
 | ||||
| 		if (!pdd->dev->driver) | ||||
| 			continue; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * Check if the device is allowed to be off long enough for the | ||||
| 		 * domain to turn off and on (that's how much time it will | ||||
|  | ||||
| @ -18,6 +18,7 @@ struct nullb_cmd { | ||||
| 	struct bio *bio; | ||||
| 	unsigned int tag; | ||||
| 	struct nullb_queue *nq; | ||||
| 	struct hrtimer timer; | ||||
| }; | ||||
| 
 | ||||
| struct nullb_queue { | ||||
| @ -49,17 +50,6 @@ static int null_major; | ||||
| static int nullb_indexes; | ||||
| static struct kmem_cache *ppa_cache; | ||||
| 
 | ||||
| struct completion_queue { | ||||
| 	struct llist_head list; | ||||
| 	struct hrtimer timer; | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * These are per-cpu for now, they will need to be configured by the | ||||
|  * complete_queues parameter and appropriately mapped. | ||||
|  */ | ||||
| static DEFINE_PER_CPU(struct completion_queue, completion_queues); | ||||
| 
 | ||||
| enum { | ||||
| 	NULL_IRQ_NONE		= 0, | ||||
| 	NULL_IRQ_SOFTIRQ	= 1, | ||||
| @ -142,8 +132,8 @@ static const struct kernel_param_ops null_irqmode_param_ops = { | ||||
| device_param_cb(irqmode, &null_irqmode_param_ops, &irqmode, S_IRUGO); | ||||
| MODULE_PARM_DESC(irqmode, "IRQ completion handler. 0-none, 1-softirq, 2-timer"); | ||||
| 
 | ||||
| static int completion_nsec = 10000; | ||||
| module_param(completion_nsec, int, S_IRUGO); | ||||
| static unsigned long completion_nsec = 10000; | ||||
| module_param(completion_nsec, ulong, S_IRUGO); | ||||
| MODULE_PARM_DESC(completion_nsec, "Time in ns to complete a request in hardware. Default: 10,000ns"); | ||||
| 
 | ||||
| static int hw_queue_depth = 64; | ||||
| @ -180,6 +170,8 @@ static void free_cmd(struct nullb_cmd *cmd) | ||||
| 	put_tag(cmd->nq, cmd->tag); | ||||
| } | ||||
| 
 | ||||
| static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer); | ||||
| 
 | ||||
| static struct nullb_cmd *__alloc_cmd(struct nullb_queue *nq) | ||||
| { | ||||
| 	struct nullb_cmd *cmd; | ||||
| @ -190,6 +182,11 @@ static struct nullb_cmd *__alloc_cmd(struct nullb_queue *nq) | ||||
| 		cmd = &nq->cmds[tag]; | ||||
| 		cmd->tag = tag; | ||||
| 		cmd->nq = nq; | ||||
| 		if (irqmode == NULL_IRQ_TIMER) { | ||||
| 			hrtimer_init(&cmd->timer, CLOCK_MONOTONIC, | ||||
| 				     HRTIMER_MODE_REL); | ||||
| 			cmd->timer.function = null_cmd_timer_expired; | ||||
| 		} | ||||
| 		return cmd; | ||||
| 	} | ||||
| 
 | ||||
| @ -220,6 +217,8 @@ static struct nullb_cmd *alloc_cmd(struct nullb_queue *nq, int can_wait) | ||||
| 
 | ||||
| static void end_cmd(struct nullb_cmd *cmd) | ||||
| { | ||||
| 	struct request_queue *q = NULL; | ||||
| 
 | ||||
| 	switch (queue_mode)  { | ||||
| 	case NULL_Q_MQ: | ||||
| 		blk_mq_end_request(cmd->rq, 0); | ||||
| @ -230,55 +229,37 @@ static void end_cmd(struct nullb_cmd *cmd) | ||||
| 		break; | ||||
| 	case NULL_Q_BIO: | ||||
| 		bio_endio(cmd->bio); | ||||
| 		break; | ||||
| 		goto free_cmd; | ||||
| 	} | ||||
| 
 | ||||
| 	if (cmd->rq) | ||||
| 		q = cmd->rq->q; | ||||
| 
 | ||||
| 	/* Restart queue if needed, as we are freeing a tag */ | ||||
| 	if (q && !q->mq_ops && blk_queue_stopped(q)) { | ||||
| 		unsigned long flags; | ||||
| 
 | ||||
| 		spin_lock_irqsave(q->queue_lock, flags); | ||||
| 		if (blk_queue_stopped(q)) | ||||
| 			blk_start_queue(q); | ||||
| 		spin_unlock_irqrestore(q->queue_lock, flags); | ||||
| 	} | ||||
| free_cmd: | ||||
| 	free_cmd(cmd); | ||||
| } | ||||
| 
 | ||||
| static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer) | ||||
| { | ||||
| 	struct completion_queue *cq; | ||||
| 	struct llist_node *entry; | ||||
| 	struct nullb_cmd *cmd; | ||||
| 
 | ||||
| 	cq = &per_cpu(completion_queues, smp_processor_id()); | ||||
| 
 | ||||
| 	while ((entry = llist_del_all(&cq->list)) != NULL) { | ||||
| 		entry = llist_reverse_order(entry); | ||||
| 		do { | ||||
| 			struct request_queue *q = NULL; | ||||
| 
 | ||||
| 			cmd = container_of(entry, struct nullb_cmd, ll_list); | ||||
| 			entry = entry->next; | ||||
| 			if (cmd->rq) | ||||
| 				q = cmd->rq->q; | ||||
| 			end_cmd(cmd); | ||||
| 
 | ||||
| 			if (q && !q->mq_ops && blk_queue_stopped(q)) { | ||||
| 				spin_lock(q->queue_lock); | ||||
| 				if (blk_queue_stopped(q)) | ||||
| 					blk_start_queue(q); | ||||
| 				spin_unlock(q->queue_lock); | ||||
| 			} | ||||
| 		} while (entry); | ||||
| 	} | ||||
| 	end_cmd(container_of(timer, struct nullb_cmd, timer)); | ||||
| 
 | ||||
| 	return HRTIMER_NORESTART; | ||||
| } | ||||
| 
 | ||||
| static void null_cmd_end_timer(struct nullb_cmd *cmd) | ||||
| { | ||||
| 	struct completion_queue *cq = &per_cpu(completion_queues, get_cpu()); | ||||
| 	ktime_t kt = ktime_set(0, completion_nsec); | ||||
| 
 | ||||
| 	cmd->ll_list.next = NULL; | ||||
| 	if (llist_add(&cmd->ll_list, &cq->list)) { | ||||
| 		ktime_t kt = ktime_set(0, completion_nsec); | ||||
| 
 | ||||
| 		hrtimer_start(&cq->timer, kt, HRTIMER_MODE_REL_PINNED); | ||||
| 	} | ||||
| 
 | ||||
| 	put_cpu(); | ||||
| 	hrtimer_start(&cmd->timer, kt, HRTIMER_MODE_REL); | ||||
| } | ||||
| 
 | ||||
| static void null_softirq_done_fn(struct request *rq) | ||||
| @ -376,6 +357,10 @@ static int null_queue_rq(struct blk_mq_hw_ctx *hctx, | ||||
| { | ||||
| 	struct nullb_cmd *cmd = blk_mq_rq_to_pdu(bd->rq); | ||||
| 
 | ||||
| 	if (irqmode == NULL_IRQ_TIMER) { | ||||
| 		hrtimer_init(&cmd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||||
| 		cmd->timer.function = null_cmd_timer_expired; | ||||
| 	} | ||||
| 	cmd->rq = bd->rq; | ||||
| 	cmd->nq = hctx->driver_data; | ||||
| 
 | ||||
| @ -813,19 +798,6 @@ static int __init null_init(void) | ||||
| 
 | ||||
| 	mutex_init(&lock); | ||||
| 
 | ||||
| 	/* Initialize a separate list for each CPU for issuing softirqs */ | ||||
| 	for_each_possible_cpu(i) { | ||||
| 		struct completion_queue *cq = &per_cpu(completion_queues, i); | ||||
| 
 | ||||
| 		init_llist_head(&cq->list); | ||||
| 
 | ||||
| 		if (irqmode != NULL_IRQ_TIMER) | ||||
| 			continue; | ||||
| 
 | ||||
| 		hrtimer_init(&cq->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||||
| 		cq->timer.function = null_cmd_timer_expired; | ||||
| 	} | ||||
| 
 | ||||
| 	null_major = register_blkdev(0, "nullb"); | ||||
| 	if (null_major < 0) | ||||
| 		return null_major; | ||||
|  | ||||
| @ -3442,6 +3442,7 @@ static void rbd_queue_workfn(struct work_struct *work) | ||||
| 		goto err_rq; | ||||
| 	} | ||||
| 	img_request->rq = rq; | ||||
| 	snapc = NULL; /* img_request consumes a ref */ | ||||
| 
 | ||||
| 	if (op_type == OBJ_OP_DISCARD) | ||||
| 		result = rbd_img_request_fill(img_request, OBJ_REQUEST_NODATA, | ||||
|  | ||||
| @ -976,10 +976,14 @@ static int cpufreq_init_policy(struct cpufreq_policy *policy) | ||||
| 
 | ||||
| 	new_policy.governor = gov; | ||||
| 
 | ||||
| 	/* Use the default policy if its valid. */ | ||||
| 	if (cpufreq_driver->setpolicy) | ||||
| 		cpufreq_parse_governor(gov->name, &new_policy.policy, NULL); | ||||
| 
 | ||||
| 	/* Use the default policy if there is no last_policy. */ | ||||
| 	if (cpufreq_driver->setpolicy) { | ||||
| 		if (policy->last_policy) | ||||
| 			new_policy.policy = policy->last_policy; | ||||
| 		else | ||||
| 			cpufreq_parse_governor(gov->name, &new_policy.policy, | ||||
| 					       NULL); | ||||
| 	} | ||||
| 	/* set default policy */ | ||||
| 	return cpufreq_set_policy(policy, &new_policy); | ||||
| } | ||||
| @ -1330,6 +1334,8 @@ static void cpufreq_offline_prepare(unsigned int cpu) | ||||
| 		if (has_target()) | ||||
| 			strncpy(policy->last_governor, policy->governor->name, | ||||
| 				CPUFREQ_NAME_LEN); | ||||
| 		else | ||||
| 			policy->last_policy = policy->policy; | ||||
| 	} else if (cpu == policy->cpu) { | ||||
| 		/* Nominate new CPU */ | ||||
| 		policy->cpu = cpumask_any(policy->cpus); | ||||
|  | ||||
| @ -409,7 +409,7 @@ static int ccm_nx_decrypt(struct aead_request   *req, | ||||
| 		processed += to_process; | ||||
| 	} while (processed < nbytes); | ||||
| 
 | ||||
| 	rc = memcmp(csbcpb->cpb.aes_ccm.out_pat_or_mac, priv->oauth_tag, | ||||
| 	rc = crypto_memneq(csbcpb->cpb.aes_ccm.out_pat_or_mac, priv->oauth_tag, | ||||
| 		    authsize) ? -EBADMSG : 0; | ||||
| out: | ||||
| 	spin_unlock_irqrestore(&nx_ctx->lock, irq_flags); | ||||
|  | ||||
| @ -21,6 +21,7 @@ | ||||
| 
 | ||||
| #include <crypto/internal/aead.h> | ||||
| #include <crypto/aes.h> | ||||
| #include <crypto/algapi.h> | ||||
| #include <crypto/scatterwalk.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/types.h> | ||||
| @ -418,7 +419,7 @@ mac: | ||||
| 			itag, req->src, req->assoclen + nbytes, | ||||
| 			crypto_aead_authsize(crypto_aead_reqtfm(req)), | ||||
| 			SCATTERWALK_FROM_SG); | ||||
| 		rc = memcmp(itag, otag, | ||||
| 		rc = crypto_memneq(itag, otag, | ||||
| 			    crypto_aead_authsize(crypto_aead_reqtfm(req))) ? | ||||
| 		     -EBADMSG : 0; | ||||
| 	} | ||||
|  | ||||
| @ -977,7 +977,7 @@ static void ipsec_esp_decrypt_swauth_done(struct device *dev, | ||||
| 		} else | ||||
| 			oicv = (char *)&edesc->link_tbl[0]; | ||||
| 
 | ||||
| 		err = memcmp(oicv, icv, authsize) ? -EBADMSG : 0; | ||||
| 		err = crypto_memneq(oicv, icv, authsize) ? -EBADMSG : 0; | ||||
| 	} | ||||
| 
 | ||||
| 	kfree(edesc); | ||||
|  | ||||
| @ -113,13 +113,16 @@ static int mmio_74xx_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) | ||||
| 
 | ||||
| static int mmio_74xx_gpio_probe(struct platform_device *pdev) | ||||
| { | ||||
| 	const struct of_device_id *of_id = | ||||
| 		of_match_device(mmio_74xx_gpio_ids, &pdev->dev); | ||||
| 	const struct of_device_id *of_id; | ||||
| 	struct mmio_74xx_gpio_priv *priv; | ||||
| 	struct resource *res; | ||||
| 	void __iomem *dat; | ||||
| 	int err; | ||||
| 
 | ||||
| 	of_id = of_match_device(mmio_74xx_gpio_ids, &pdev->dev); | ||||
| 	if (!of_id) | ||||
| 		return -ENODEV; | ||||
| 
 | ||||
| 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | ||||
| 	if (!priv) | ||||
| 		return -ENOMEM; | ||||
|  | ||||
| @ -1122,8 +1122,6 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) | ||||
| 	/* MPUIO is a bit different, reading IRQ status clears it */ | ||||
| 	if (bank->is_mpuio) { | ||||
| 		irqc->irq_ack = dummy_irq_chip.irq_ack; | ||||
| 		irqc->irq_mask = irq_gc_mask_set_bit; | ||||
| 		irqc->irq_unmask = irq_gc_mask_clr_bit; | ||||
| 		if (!bank->regs->wkup_en) | ||||
| 			irqc->irq_set_wake = NULL; | ||||
| 	} | ||||
|  | ||||
| @ -167,6 +167,8 @@ static int palmas_gpio_probe(struct platform_device *pdev) | ||||
| 	const struct palmas_device_data *dev_data; | ||||
| 
 | ||||
| 	match = of_match_device(of_palmas_gpio_match, &pdev->dev); | ||||
| 	if (!match) | ||||
| 		return -ENODEV; | ||||
| 	dev_data = match->data; | ||||
| 	if (!dev_data) | ||||
| 		dev_data = &palmas_dev_data; | ||||
|  | ||||
| @ -187,11 +187,15 @@ MODULE_DEVICE_TABLE(of, syscon_gpio_ids); | ||||
| static int syscon_gpio_probe(struct platform_device *pdev) | ||||
| { | ||||
| 	struct device *dev = &pdev->dev; | ||||
| 	const struct of_device_id *of_id = of_match_device(syscon_gpio_ids, dev); | ||||
| 	const struct of_device_id *of_id; | ||||
| 	struct syscon_gpio_priv *priv; | ||||
| 	struct device_node *np = dev->of_node; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	of_id = of_match_device(syscon_gpio_ids, dev); | ||||
| 	if (!of_id) | ||||
| 		return -ENODEV; | ||||
| 
 | ||||
| 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||||
| 	if (!priv) | ||||
| 		return -ENOMEM; | ||||
|  | ||||
| @ -375,6 +375,60 @@ static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #ifdef	CONFIG_DEBUG_FS | ||||
| 
 | ||||
| #include <linux/debugfs.h> | ||||
| #include <linux/seq_file.h> | ||||
| 
 | ||||
| static int dbg_gpio_show(struct seq_file *s, void *unused) | ||||
| { | ||||
| 	int i; | ||||
| 	int j; | ||||
| 
 | ||||
| 	for (i = 0; i < tegra_gpio_bank_count; i++) { | ||||
| 		for (j = 0; j < 4; j++) { | ||||
| 			int gpio = tegra_gpio_compose(i, j, 0); | ||||
| 			seq_printf(s, | ||||
| 				"%d:%d %02x %02x %02x %02x %02x %02x %06x\n", | ||||
| 				i, j, | ||||
| 				tegra_gpio_readl(GPIO_CNF(gpio)), | ||||
| 				tegra_gpio_readl(GPIO_OE(gpio)), | ||||
| 				tegra_gpio_readl(GPIO_OUT(gpio)), | ||||
| 				tegra_gpio_readl(GPIO_IN(gpio)), | ||||
| 				tegra_gpio_readl(GPIO_INT_STA(gpio)), | ||||
| 				tegra_gpio_readl(GPIO_INT_ENB(gpio)), | ||||
| 				tegra_gpio_readl(GPIO_INT_LVL(gpio))); | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int dbg_gpio_open(struct inode *inode, struct file *file) | ||||
| { | ||||
| 	return single_open(file, dbg_gpio_show, &inode->i_private); | ||||
| } | ||||
| 
 | ||||
| static const struct file_operations debug_fops = { | ||||
| 	.open		= dbg_gpio_open, | ||||
| 	.read		= seq_read, | ||||
| 	.llseek		= seq_lseek, | ||||
| 	.release	= single_release, | ||||
| }; | ||||
| 
 | ||||
| static void tegra_gpio_debuginit(void) | ||||
| { | ||||
| 	(void) debugfs_create_file("tegra_gpio", S_IRUGO, | ||||
| 					NULL, NULL, &debug_fops); | ||||
| } | ||||
| 
 | ||||
| #else | ||||
| 
 | ||||
| static inline void tegra_gpio_debuginit(void) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| static struct irq_chip tegra_gpio_irq_chip = { | ||||
| 	.name		= "GPIO", | ||||
| 	.irq_ack	= tegra_gpio_irq_ack, | ||||
| @ -519,6 +573,8 @@ static int tegra_gpio_probe(struct platform_device *pdev) | ||||
| 			spin_lock_init(&bank->lvl_lock[j]); | ||||
| 	} | ||||
| 
 | ||||
| 	tegra_gpio_debuginit(); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -536,52 +592,3 @@ static int __init tegra_gpio_init(void) | ||||
| 	return platform_driver_register(&tegra_gpio_driver); | ||||
| } | ||||
| postcore_initcall(tegra_gpio_init); | ||||
| 
 | ||||
| #ifdef	CONFIG_DEBUG_FS | ||||
| 
 | ||||
| #include <linux/debugfs.h> | ||||
| #include <linux/seq_file.h> | ||||
| 
 | ||||
| static int dbg_gpio_show(struct seq_file *s, void *unused) | ||||
| { | ||||
| 	int i; | ||||
| 	int j; | ||||
| 
 | ||||
| 	for (i = 0; i < tegra_gpio_bank_count; i++) { | ||||
| 		for (j = 0; j < 4; j++) { | ||||
| 			int gpio = tegra_gpio_compose(i, j, 0); | ||||
| 			seq_printf(s, | ||||
| 				"%d:%d %02x %02x %02x %02x %02x %02x %06x\n", | ||||
| 				i, j, | ||||
| 				tegra_gpio_readl(GPIO_CNF(gpio)), | ||||
| 				tegra_gpio_readl(GPIO_OE(gpio)), | ||||
| 				tegra_gpio_readl(GPIO_OUT(gpio)), | ||||
| 				tegra_gpio_readl(GPIO_IN(gpio)), | ||||
| 				tegra_gpio_readl(GPIO_INT_STA(gpio)), | ||||
| 				tegra_gpio_readl(GPIO_INT_ENB(gpio)), | ||||
| 				tegra_gpio_readl(GPIO_INT_LVL(gpio))); | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int dbg_gpio_open(struct inode *inode, struct file *file) | ||||
| { | ||||
| 	return single_open(file, dbg_gpio_show, &inode->i_private); | ||||
| } | ||||
| 
 | ||||
| static const struct file_operations debug_fops = { | ||||
| 	.open		= dbg_gpio_open, | ||||
| 	.read		= seq_read, | ||||
| 	.llseek		= seq_lseek, | ||||
| 	.release	= single_release, | ||||
| }; | ||||
| 
 | ||||
| static int __init tegra_gpio_debuginit(void) | ||||
| { | ||||
| 	(void) debugfs_create_file("tegra_gpio", S_IRUGO, | ||||
| 					NULL, NULL, &debug_fops); | ||||
| 	return 0; | ||||
| } | ||||
| late_initcall(tegra_gpio_debuginit); | ||||
| #endif | ||||
|  | ||||
| @ -233,7 +233,7 @@ static struct gpio_desc *gpio_name_to_desc(const char * const name) | ||||
| 		for (i = 0; i != chip->ngpio; ++i) { | ||||
| 			struct gpio_desc *gpio = &chip->desc[i]; | ||||
| 
 | ||||
| 			if (!gpio->name) | ||||
| 			if (!gpio->name || !name) | ||||
| 				continue; | ||||
| 
 | ||||
| 			if (!strcmp(gpio->name, name)) { | ||||
|  | ||||
| @ -539,6 +539,7 @@ struct amdgpu_bo { | ||||
| 	/* Constant after initialization */ | ||||
| 	struct amdgpu_device		*adev; | ||||
| 	struct drm_gem_object		gem_base; | ||||
| 	struct amdgpu_bo		*parent; | ||||
| 
 | ||||
| 	struct ttm_bo_kmap_obj		dma_buf_vmap; | ||||
| 	pid_t				pid; | ||||
| @ -955,6 +956,8 @@ struct amdgpu_vm { | ||||
| 	struct amdgpu_vm_id	ids[AMDGPU_MAX_RINGS]; | ||||
| 	/* for interval tree */ | ||||
| 	spinlock_t		it_lock; | ||||
| 	/* protecting freed */ | ||||
| 	spinlock_t		freed_lock; | ||||
| }; | ||||
| 
 | ||||
| struct amdgpu_vm_manager { | ||||
|  | ||||
| @ -222,6 +222,8 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) | ||||
| 				} | ||||
| 
 | ||||
| 				p->uf.bo = gem_to_amdgpu_bo(gobj); | ||||
| 				amdgpu_bo_ref(p->uf.bo); | ||||
| 				drm_gem_object_unreference_unlocked(gobj); | ||||
| 				p->uf.offset = fence_data->offset; | ||||
| 			} else { | ||||
| 				ret = -EINVAL; | ||||
| @ -487,7 +489,7 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, bo | ||||
| 			amdgpu_ib_free(parser->adev, &parser->ibs[i]); | ||||
| 	kfree(parser->ibs); | ||||
| 	if (parser->uf.bo) | ||||
| 		drm_gem_object_unreference_unlocked(&parser->uf.bo->gem_base); | ||||
| 		amdgpu_bo_unref(&parser->uf.bo); | ||||
| } | ||||
| 
 | ||||
| static int amdgpu_bo_vm_update_pte(struct amdgpu_cs_parser *p, | ||||
| @ -776,7 +778,7 @@ static int amdgpu_cs_free_job(struct amdgpu_job *job) | ||||
| 			amdgpu_ib_free(job->adev, &job->ibs[i]); | ||||
| 	kfree(job->ibs); | ||||
| 	if (job->uf.bo) | ||||
| 		drm_gem_object_unreference_unlocked(&job->uf.bo->gem_base); | ||||
| 		amdgpu_bo_unref(&job->uf.bo); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -73,6 +73,8 @@ static void amdgpu_flip_work_func(struct work_struct *__work) | ||||
| 	struct drm_crtc *crtc = &amdgpuCrtc->base; | ||||
| 	unsigned long flags; | ||||
| 	unsigned i; | ||||
| 	int vpos, hpos, stat, min_udelay; | ||||
| 	struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id]; | ||||
| 
 | ||||
| 	amdgpu_flip_wait_fence(adev, &work->excl); | ||||
| 	for (i = 0; i < work->shared_count; ++i) | ||||
| @ -81,6 +83,41 @@ static void amdgpu_flip_work_func(struct work_struct *__work) | ||||
| 	/* We borrow the event spin lock for protecting flip_status */ | ||||
| 	spin_lock_irqsave(&crtc->dev->event_lock, flags); | ||||
| 
 | ||||
| 	/* If this happens to execute within the "virtually extended" vblank
 | ||||
| 	 * interval before the start of the real vblank interval then it needs | ||||
| 	 * to delay programming the mmio flip until the real vblank is entered. | ||||
| 	 * This prevents completing a flip too early due to the way we fudge | ||||
| 	 * our vblank counter and vblank timestamps in order to work around the | ||||
| 	 * problem that the hw fires vblank interrupts before actual start of | ||||
| 	 * vblank (when line buffer refilling is done for a frame). It | ||||
| 	 * complements the fudging logic in amdgpu_get_crtc_scanoutpos() for | ||||
| 	 * timestamping and amdgpu_get_vblank_counter_kms() for vblank counts. | ||||
| 	 * | ||||
| 	 * In practice this won't execute very often unless on very fast | ||||
| 	 * machines because the time window for this to happen is very small. | ||||
| 	 */ | ||||
| 	for (;;) { | ||||
| 		/* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank
 | ||||
| 		 * start in hpos, and to the "fudged earlier" vblank start in | ||||
| 		 * vpos. | ||||
| 		 */ | ||||
| 		stat = amdgpu_get_crtc_scanoutpos(adev->ddev, work->crtc_id, | ||||
| 						  GET_DISTANCE_TO_VBLANKSTART, | ||||
| 						  &vpos, &hpos, NULL, NULL, | ||||
| 						  &crtc->hwmode); | ||||
| 
 | ||||
| 		if ((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) != | ||||
| 		    (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE) || | ||||
| 		    !(vpos >= 0 && hpos <= 0)) | ||||
| 			break; | ||||
| 
 | ||||
| 		/* Sleep at least until estimated real start of hw vblank */ | ||||
| 		spin_unlock_irqrestore(&crtc->dev->event_lock, flags); | ||||
| 		min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5); | ||||
| 		usleep_range(min_udelay, 2 * min_udelay); | ||||
| 		spin_lock_irqsave(&crtc->dev->event_lock, flags); | ||||
| 	}; | ||||
| 
 | ||||
| 	/* do the flip (mmio) */ | ||||
| 	adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base); | ||||
| 	/* set the flip status */ | ||||
| @ -109,7 +146,7 @@ static void amdgpu_unpin_work_func(struct work_struct *__work) | ||||
| 	} else | ||||
| 		DRM_ERROR("failed to reserve buffer after flip\n"); | ||||
| 
 | ||||
| 	drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base); | ||||
| 	amdgpu_bo_unref(&work->old_rbo); | ||||
| 	kfree(work->shared); | ||||
| 	kfree(work); | ||||
| } | ||||
| @ -148,8 +185,8 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc, | ||||
| 	obj = old_amdgpu_fb->obj; | ||||
| 
 | ||||
| 	/* take a reference to the old object */ | ||||
| 	drm_gem_object_reference(obj); | ||||
| 	work->old_rbo = gem_to_amdgpu_bo(obj); | ||||
| 	amdgpu_bo_ref(work->old_rbo); | ||||
| 
 | ||||
| 	new_amdgpu_fb = to_amdgpu_framebuffer(fb); | ||||
| 	obj = new_amdgpu_fb->obj; | ||||
| @ -222,7 +259,7 @@ pflip_cleanup: | ||||
| 	amdgpu_bo_unreserve(new_rbo); | ||||
| 
 | ||||
| cleanup: | ||||
| 	drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base); | ||||
| 	amdgpu_bo_unref(&work->old_rbo); | ||||
| 	fence_put(work->excl); | ||||
| 	for (i = 0; i < work->shared_count; ++i) | ||||
| 		fence_put(work->shared[i]); | ||||
| @ -712,6 +749,15 @@ bool amdgpu_crtc_scaling_mode_fixup(struct drm_crtc *crtc, | ||||
|  * \param dev Device to query. | ||||
|  * \param pipe Crtc to query. | ||||
|  * \param flags Flags from caller (DRM_CALLED_FROM_VBLIRQ or 0). | ||||
|  *              For driver internal use only also supports these flags: | ||||
|  * | ||||
|  *              USE_REAL_VBLANKSTART to use the real start of vblank instead | ||||
|  *              of a fudged earlier start of vblank. | ||||
|  * | ||||
|  *              GET_DISTANCE_TO_VBLANKSTART to return distance to the | ||||
|  *              fudged earlier start of vblank in *vpos and the distance | ||||
|  *              to true start of vblank in *hpos. | ||||
|  * | ||||
|  * \param *vpos Location where vertical scanout position should be stored. | ||||
|  * \param *hpos Location where horizontal scanout position should go. | ||||
|  * \param *stime Target location for timestamp taken immediately before | ||||
| @ -776,10 +822,40 @@ int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, | ||||
| 		vbl_end = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Called from driver internal vblank counter query code? */ | ||||
| 	if (flags & GET_DISTANCE_TO_VBLANKSTART) { | ||||
| 	    /* Caller wants distance from real vbl_start in *hpos */ | ||||
| 	    *hpos = *vpos - vbl_start; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Fudge vblank to start a few scanlines earlier to handle the
 | ||||
| 	 * problem that vblank irqs fire a few scanlines before start | ||||
| 	 * of vblank. Some driver internal callers need the true vblank | ||||
| 	 * start to be used and signal this via the USE_REAL_VBLANKSTART flag. | ||||
| 	 * | ||||
| 	 * The cause of the "early" vblank irq is that the irq is triggered | ||||
| 	 * by the line buffer logic when the line buffer read position enters | ||||
| 	 * the vblank, whereas our crtc scanout position naturally lags the | ||||
| 	 * line buffer read position. | ||||
| 	 */ | ||||
| 	if (!(flags & USE_REAL_VBLANKSTART)) | ||||
| 		vbl_start -= adev->mode_info.crtcs[pipe]->lb_vblank_lead_lines; | ||||
| 
 | ||||
| 	/* Test scanout position against vblank region. */ | ||||
| 	if ((*vpos < vbl_start) && (*vpos >= vbl_end)) | ||||
| 		in_vbl = false; | ||||
| 
 | ||||
| 	/* In vblank? */ | ||||
| 	if (in_vbl) | ||||
| 	    ret |= DRM_SCANOUTPOS_IN_VBLANK; | ||||
| 
 | ||||
| 	/* Called from driver internal vblank counter query code? */ | ||||
| 	if (flags & GET_DISTANCE_TO_VBLANKSTART) { | ||||
| 		/* Caller wants distance from fudged earlier vbl_start */ | ||||
| 		*vpos -= vbl_start; | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Check if inside vblank area and apply corrective offsets:
 | ||||
| 	 * vpos will then be >=0 in video scanout area, but negative | ||||
| 	 * within vblank area, counting down the number of lines until | ||||
| @ -795,32 +871,6 @@ int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, | ||||
| 	/* Correct for shifted end of vbl at vbl_end. */ | ||||
| 	*vpos = *vpos - vbl_end; | ||||
| 
 | ||||
| 	/* In vblank? */ | ||||
| 	if (in_vbl) | ||||
| 		ret |= DRM_SCANOUTPOS_IN_VBLANK; | ||||
| 
 | ||||
| 	/* Is vpos outside nominal vblank area, but less than
 | ||||
| 	 * 1/100 of a frame height away from start of vblank? | ||||
| 	 * If so, assume this isn't a massively delayed vblank | ||||
| 	 * interrupt, but a vblank interrupt that fired a few | ||||
| 	 * microseconds before true start of vblank. Compensate | ||||
| 	 * by adding a full frame duration to the final timestamp. | ||||
| 	 * Happens, e.g., on ATI R500, R600. | ||||
| 	 * | ||||
| 	 * We only do this if DRM_CALLED_FROM_VBLIRQ. | ||||
| 	 */ | ||||
| 	if ((flags & DRM_CALLED_FROM_VBLIRQ) && !in_vbl) { | ||||
| 		vbl_start = mode->crtc_vdisplay; | ||||
| 		vtotal = mode->crtc_vtotal; | ||||
| 
 | ||||
| 		if (vbl_start - *vpos < vtotal / 100) { | ||||
| 			*vpos -= vtotal; | ||||
| 
 | ||||
| 			/* Signal this correction as "applied". */ | ||||
| 			ret |= 0x8; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -235,8 +235,9 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data, | ||||
| 	    AMDGPU_GEM_USERPTR_REGISTER)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	if (!(args->flags & AMDGPU_GEM_USERPTR_ANONONLY) || | ||||
| 		   !(args->flags & AMDGPU_GEM_USERPTR_REGISTER)) { | ||||
| 	if (!(args->flags & AMDGPU_GEM_USERPTR_READONLY) && ( | ||||
| 	     !(args->flags & AMDGPU_GEM_USERPTR_ANONONLY) || | ||||
| 	     !(args->flags & AMDGPU_GEM_USERPTR_REGISTER))) { | ||||
| 
 | ||||
| 		/* if we want to write to it we must require anonymous
 | ||||
| 		   memory and install a MMU notifier */ | ||||
|  | ||||
| @ -611,13 +611,59 @@ void amdgpu_driver_preclose_kms(struct drm_device *dev, | ||||
| u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe) | ||||
| { | ||||
| 	struct amdgpu_device *adev = dev->dev_private; | ||||
| 	int vpos, hpos, stat; | ||||
| 	u32 count; | ||||
| 
 | ||||
| 	if (pipe >= adev->mode_info.num_crtc) { | ||||
| 		DRM_ERROR("Invalid crtc %u\n", pipe); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	return amdgpu_display_vblank_get_counter(adev, pipe); | ||||
| 	/* The hw increments its frame counter at start of vsync, not at start
 | ||||
| 	 * of vblank, as is required by DRM core vblank counter handling. | ||||
| 	 * Cook the hw count here to make it appear to the caller as if it | ||||
| 	 * incremented at start of vblank. We measure distance to start of | ||||
| 	 * vblank in vpos. vpos therefore will be >= 0 between start of vblank | ||||
| 	 * and start of vsync, so vpos >= 0 means to bump the hw frame counter | ||||
| 	 * result by 1 to give the proper appearance to caller. | ||||
| 	 */ | ||||
| 	if (adev->mode_info.crtcs[pipe]) { | ||||
| 		/* Repeat readout if needed to provide stable result if
 | ||||
| 		 * we cross start of vsync during the queries. | ||||
| 		 */ | ||||
| 		do { | ||||
| 			count = amdgpu_display_vblank_get_counter(adev, pipe); | ||||
| 			/* Ask amdgpu_get_crtc_scanoutpos to return vpos as
 | ||||
| 			 * distance to start of vblank, instead of regular | ||||
| 			 * vertical scanout pos. | ||||
| 			 */ | ||||
| 			stat = amdgpu_get_crtc_scanoutpos( | ||||
| 				dev, pipe, GET_DISTANCE_TO_VBLANKSTART, | ||||
| 				&vpos, &hpos, NULL, NULL, | ||||
| 				&adev->mode_info.crtcs[pipe]->base.hwmode); | ||||
| 		} while (count != amdgpu_display_vblank_get_counter(adev, pipe)); | ||||
| 
 | ||||
| 		if (((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) != | ||||
| 		    (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE))) { | ||||
| 			DRM_DEBUG_VBL("Query failed! stat %d\n", stat); | ||||
| 		} else { | ||||
| 			DRM_DEBUG_VBL("crtc %d: dist from vblank start %d\n", | ||||
| 				      pipe, vpos); | ||||
| 
 | ||||
| 			/* Bump counter if we are at >= leading edge of vblank,
 | ||||
| 			 * but before vsync where vpos would turn negative and | ||||
| 			 * the hw counter really increments. | ||||
| 			 */ | ||||
| 			if (vpos >= 0) | ||||
| 				count++; | ||||
| 		} | ||||
| 	} else { | ||||
| 		/* Fallback to use value as is. */ | ||||
| 		count = amdgpu_display_vblank_get_counter(adev, pipe); | ||||
| 		DRM_DEBUG_VBL("NULL mode info! Returned count may be wrong.\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	return count; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  | ||||
| @ -407,6 +407,7 @@ struct amdgpu_crtc { | ||||
| 	u32 line_time; | ||||
| 	u32 wm_low; | ||||
| 	u32 wm_high; | ||||
| 	u32 lb_vblank_lead_lines; | ||||
| 	struct drm_display_mode hw_mode; | ||||
| }; | ||||
| 
 | ||||
| @ -528,6 +529,10 @@ struct amdgpu_framebuffer { | ||||
| #define ENCODER_MODE_IS_DP(em) (((em) == ATOM_ENCODER_MODE_DP) || \ | ||||
| 				((em) == ATOM_ENCODER_MODE_DP_MST)) | ||||
| 
 | ||||
| /* Driver internal use only flags of amdgpu_get_crtc_scanoutpos() */ | ||||
| #define USE_REAL_VBLANKSTART 		(1 << 30) | ||||
| #define GET_DISTANCE_TO_VBLANKSTART	(1 << 31) | ||||
| 
 | ||||
| void amdgpu_link_encoder_connector(struct drm_device *dev); | ||||
| 
 | ||||
| struct drm_connector * | ||||
|  | ||||
| @ -100,6 +100,7 @@ static void amdgpu_ttm_bo_destroy(struct ttm_buffer_object *tbo) | ||||
| 	list_del_init(&bo->list); | ||||
| 	mutex_unlock(&bo->adev->gem.mutex); | ||||
| 	drm_gem_object_release(&bo->gem_base); | ||||
| 	amdgpu_bo_unref(&bo->parent); | ||||
| 	kfree(bo->metadata); | ||||
| 	kfree(bo); | ||||
| } | ||||
|  | ||||
| @ -587,9 +587,13 @@ static int amdgpu_ttm_backend_bind(struct ttm_tt *ttm, | ||||
| 	uint32_t flags = amdgpu_ttm_tt_pte_flags(gtt->adev, ttm, bo_mem); | ||||
| 	int r; | ||||
| 
 | ||||
| 	if (gtt->userptr) | ||||
| 		amdgpu_ttm_tt_pin_userptr(ttm); | ||||
| 
 | ||||
| 	if (gtt->userptr) { | ||||
| 		r = amdgpu_ttm_tt_pin_userptr(ttm); | ||||
| 		if (r) { | ||||
| 			DRM_ERROR("failed to pin userptr\n"); | ||||
| 			return r; | ||||
| 		} | ||||
| 	} | ||||
| 	gtt->offset = (unsigned long)(bo_mem->start << PAGE_SHIFT); | ||||
| 	if (!ttm->num_pages) { | ||||
| 		WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n", | ||||
| @ -797,11 +801,12 @@ uint32_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm, | ||||
| 	if (mem && mem->mem_type != TTM_PL_SYSTEM) | ||||
| 		flags |= AMDGPU_PTE_VALID; | ||||
| 
 | ||||
| 	if (mem && mem->mem_type == TTM_PL_TT) | ||||
| 	if (mem && mem->mem_type == TTM_PL_TT) { | ||||
| 		flags |= AMDGPU_PTE_SYSTEM; | ||||
| 
 | ||||
| 	if (!ttm || ttm->caching_state == tt_cached) | ||||
| 		flags |= AMDGPU_PTE_SNOOPED; | ||||
| 		if (ttm->caching_state == tt_cached) | ||||
| 			flags |= AMDGPU_PTE_SNOOPED; | ||||
| 	} | ||||
| 
 | ||||
| 	if (adev->asic_type >= CHIP_TOPAZ) | ||||
| 		flags |= AMDGPU_PTE_EXECUTABLE; | ||||
|  | ||||
| @ -885,17 +885,21 @@ int amdgpu_vm_clear_freed(struct amdgpu_device *adev, | ||||
| 	struct amdgpu_bo_va_mapping *mapping; | ||||
| 	int r; | ||||
| 
 | ||||
| 	spin_lock(&vm->freed_lock); | ||||
| 	while (!list_empty(&vm->freed)) { | ||||
| 		mapping = list_first_entry(&vm->freed, | ||||
| 			struct amdgpu_bo_va_mapping, list); | ||||
| 		list_del(&mapping->list); | ||||
| 
 | ||||
| 		spin_unlock(&vm->freed_lock); | ||||
| 		r = amdgpu_vm_bo_update_mapping(adev, vm, mapping, 0, 0, NULL); | ||||
| 		kfree(mapping); | ||||
| 		if (r) | ||||
| 			return r; | ||||
| 
 | ||||
| 		spin_lock(&vm->freed_lock); | ||||
| 	} | ||||
| 	spin_unlock(&vm->freed_lock); | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| } | ||||
| @ -1079,6 +1083,11 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev, | ||||
| 		if (r) | ||||
| 			goto error_free; | ||||
| 
 | ||||
| 		/* Keep a reference to the page table to avoid freeing
 | ||||
| 		 * them up in the wrong order. | ||||
| 		 */ | ||||
| 		pt->parent = amdgpu_bo_ref(vm->page_directory); | ||||
| 
 | ||||
| 		r = amdgpu_vm_clear_bo(adev, pt); | ||||
| 		if (r) { | ||||
| 			amdgpu_bo_unref(&pt); | ||||
| @ -1150,10 +1159,13 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev, | ||||
| 	spin_unlock(&vm->it_lock); | ||||
| 	trace_amdgpu_vm_bo_unmap(bo_va, mapping); | ||||
| 
 | ||||
| 	if (valid) | ||||
| 	if (valid) { | ||||
| 		spin_lock(&vm->freed_lock); | ||||
| 		list_add(&mapping->list, &vm->freed); | ||||
| 	else | ||||
| 		spin_unlock(&vm->freed_lock); | ||||
| 	} else { | ||||
| 		kfree(mapping); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| @ -1186,7 +1198,9 @@ void amdgpu_vm_bo_rmv(struct amdgpu_device *adev, | ||||
| 		interval_tree_remove(&mapping->it, &vm->va); | ||||
| 		spin_unlock(&vm->it_lock); | ||||
| 		trace_amdgpu_vm_bo_unmap(bo_va, mapping); | ||||
| 		spin_lock(&vm->freed_lock); | ||||
| 		list_add(&mapping->list, &vm->freed); | ||||
| 		spin_unlock(&vm->freed_lock); | ||||
| 	} | ||||
| 	list_for_each_entry_safe(mapping, next, &bo_va->invalids, list) { | ||||
| 		list_del(&mapping->list); | ||||
| @ -1247,6 +1261,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm) | ||||
| 	INIT_LIST_HEAD(&vm->cleared); | ||||
| 	INIT_LIST_HEAD(&vm->freed); | ||||
| 	spin_lock_init(&vm->it_lock); | ||||
| 	spin_lock_init(&vm->freed_lock); | ||||
| 	pd_size = amdgpu_vm_directory_size(adev); | ||||
| 	pd_entries = amdgpu_vm_num_pdes(adev); | ||||
| 
 | ||||
|  | ||||
| @ -1250,7 +1250,7 @@ static void dce_v10_0_program_watermarks(struct amdgpu_device *adev, | ||||
| 	u32 pixel_period; | ||||
| 	u32 line_time = 0; | ||||
| 	u32 latency_watermark_a = 0, latency_watermark_b = 0; | ||||
| 	u32 tmp, wm_mask; | ||||
| 	u32 tmp, wm_mask, lb_vblank_lead_lines = 0; | ||||
| 
 | ||||
| 	if (amdgpu_crtc->base.enabled && num_heads && mode) { | ||||
| 		pixel_period = 1000000 / (u32)mode->clock; | ||||
| @ -1333,6 +1333,7 @@ static void dce_v10_0_program_watermarks(struct amdgpu_device *adev, | ||||
| 		    (adev->mode_info.disp_priority == 2)) { | ||||
| 			DRM_DEBUG_KMS("force priority to high\n"); | ||||
| 		} | ||||
| 		lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay); | ||||
| 	} | ||||
| 
 | ||||
| 	/* select wm A */ | ||||
| @ -1357,6 +1358,8 @@ static void dce_v10_0_program_watermarks(struct amdgpu_device *adev, | ||||
| 	amdgpu_crtc->line_time = line_time; | ||||
| 	amdgpu_crtc->wm_high = latency_watermark_a; | ||||
| 	amdgpu_crtc->wm_low = latency_watermark_b; | ||||
| 	/* Save number of lines the linebuffer leads before the scanout */ | ||||
| 	amdgpu_crtc->lb_vblank_lead_lines = lb_vblank_lead_lines; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  | ||||
| @ -1238,7 +1238,7 @@ static void dce_v11_0_program_watermarks(struct amdgpu_device *adev, | ||||
| 	u32 pixel_period; | ||||
| 	u32 line_time = 0; | ||||
| 	u32 latency_watermark_a = 0, latency_watermark_b = 0; | ||||
| 	u32 tmp, wm_mask; | ||||
| 	u32 tmp, wm_mask, lb_vblank_lead_lines = 0; | ||||
| 
 | ||||
| 	if (amdgpu_crtc->base.enabled && num_heads && mode) { | ||||
| 		pixel_period = 1000000 / (u32)mode->clock; | ||||
| @ -1321,6 +1321,7 @@ static void dce_v11_0_program_watermarks(struct amdgpu_device *adev, | ||||
| 		    (adev->mode_info.disp_priority == 2)) { | ||||
| 			DRM_DEBUG_KMS("force priority to high\n"); | ||||
| 		} | ||||
| 		lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay); | ||||
| 	} | ||||
| 
 | ||||
| 	/* select wm A */ | ||||
| @ -1345,6 +1346,8 @@ static void dce_v11_0_program_watermarks(struct amdgpu_device *adev, | ||||
| 	amdgpu_crtc->line_time = line_time; | ||||
| 	amdgpu_crtc->wm_high = latency_watermark_a; | ||||
| 	amdgpu_crtc->wm_low = latency_watermark_b; | ||||
| 	/* Save number of lines the linebuffer leads before the scanout */ | ||||
| 	amdgpu_crtc->lb_vblank_lead_lines = lb_vblank_lead_lines; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  | ||||
| @ -1193,7 +1193,7 @@ static void dce_v8_0_program_watermarks(struct amdgpu_device *adev, | ||||
| 	u32 pixel_period; | ||||
| 	u32 line_time = 0; | ||||
| 	u32 latency_watermark_a = 0, latency_watermark_b = 0; | ||||
| 	u32 tmp, wm_mask; | ||||
| 	u32 tmp, wm_mask, lb_vblank_lead_lines = 0; | ||||
| 
 | ||||
| 	if (amdgpu_crtc->base.enabled && num_heads && mode) { | ||||
| 		pixel_period = 1000000 / (u32)mode->clock; | ||||
| @ -1276,6 +1276,7 @@ static void dce_v8_0_program_watermarks(struct amdgpu_device *adev, | ||||
| 		    (adev->mode_info.disp_priority == 2)) { | ||||
| 			DRM_DEBUG_KMS("force priority to high\n"); | ||||
| 		} | ||||
| 		lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay); | ||||
| 	} | ||||
| 
 | ||||
| 	/* select wm A */ | ||||
| @ -1302,6 +1303,8 @@ static void dce_v8_0_program_watermarks(struct amdgpu_device *adev, | ||||
| 	amdgpu_crtc->line_time = line_time; | ||||
| 	amdgpu_crtc->wm_high = latency_watermark_a; | ||||
| 	amdgpu_crtc->wm_low = latency_watermark_b; | ||||
| 	/* Save number of lines the linebuffer leads before the scanout */ | ||||
| 	amdgpu_crtc->lb_vblank_lead_lines = lb_vblank_lead_lines; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  | ||||
| @ -513,7 +513,7 @@ static int gmc_v7_0_gart_enable(struct amdgpu_device *adev) | ||||
| 	WREG32(mmVM_L2_CNTL3, tmp); | ||||
| 	/* setup context0 */ | ||||
| 	WREG32(mmVM_CONTEXT0_PAGE_TABLE_START_ADDR, adev->mc.gtt_start >> 12); | ||||
| 	WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, (adev->mc.gtt_end >> 12) - 1); | ||||
| 	WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, adev->mc.gtt_end >> 12); | ||||
| 	WREG32(mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR, adev->gart.table_addr >> 12); | ||||
| 	WREG32(mmVM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR, | ||||
| 			(u32)(adev->dummy_page.addr >> 12)); | ||||
|  | ||||
| @ -657,7 +657,7 @@ static int gmc_v8_0_gart_enable(struct amdgpu_device *adev) | ||||
| 	WREG32(mmVM_L2_CNTL4, tmp); | ||||
| 	/* setup context0 */ | ||||
| 	WREG32(mmVM_CONTEXT0_PAGE_TABLE_START_ADDR, adev->mc.gtt_start >> 12); | ||||
| 	WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, (adev->mc.gtt_end >> 12) - 1); | ||||
| 	WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, adev->mc.gtt_end >> 12); | ||||
| 	WREG32(mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR, adev->gart.table_addr >> 12); | ||||
| 	WREG32(mmVM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR, | ||||
| 			(u32)(adev->dummy_page.addr >> 12)); | ||||
|  | ||||
| @ -288,6 +288,7 @@ amd_sched_entity_pop_job(struct amd_sched_entity *entity) | ||||
|  */ | ||||
| static bool amd_sched_entity_in(struct amd_sched_job *sched_job) | ||||
| { | ||||
| 	struct amd_gpu_scheduler *sched = sched_job->sched; | ||||
| 	struct amd_sched_entity *entity = sched_job->s_entity; | ||||
| 	bool added, first = false; | ||||
| 
 | ||||
| @ -302,7 +303,7 @@ static bool amd_sched_entity_in(struct amd_sched_job *sched_job) | ||||
| 
 | ||||
| 	/* first job wakes up scheduler */ | ||||
| 	if (first) | ||||
| 		amd_sched_wakeup(sched_job->sched); | ||||
| 		amd_sched_wakeup(sched); | ||||
| 
 | ||||
| 	return added; | ||||
| } | ||||
| @ -318,9 +319,9 @@ void amd_sched_entity_push_job(struct amd_sched_job *sched_job) | ||||
| { | ||||
| 	struct amd_sched_entity *entity = sched_job->s_entity; | ||||
| 
 | ||||
| 	trace_amd_sched_job(sched_job); | ||||
| 	wait_event(entity->sched->job_scheduled, | ||||
| 		   amd_sched_entity_in(sched_job)); | ||||
| 	trace_amd_sched_job(sched_job); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  | ||||
| @ -160,6 +160,11 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data, | ||||
| 		goto out_unlock; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!file_priv->allowed_master) { | ||||
| 		ret = drm_new_set_master(dev, file_priv); | ||||
| 		goto out_unlock; | ||||
| 	} | ||||
| 
 | ||||
| 	file_priv->minor->master = drm_master_get(file_priv->master); | ||||
| 	file_priv->is_master = 1; | ||||
| 	if (dev->driver->master_set) { | ||||
|  | ||||
| @ -125,6 +125,60 @@ static int drm_cpu_valid(void) | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * drm_new_set_master - Allocate a new master object and become master for the | ||||
|  * associated master realm. | ||||
|  * | ||||
|  * @dev: The associated device. | ||||
|  * @fpriv: File private identifying the client. | ||||
|  * | ||||
|  * This function must be called with dev::struct_mutex held. | ||||
|  * Returns negative error code on failure. Zero on success. | ||||
|  */ | ||||
| int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv) | ||||
| { | ||||
| 	struct drm_master *old_master; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	lockdep_assert_held_once(&dev->master_mutex); | ||||
| 
 | ||||
| 	/* create a new master */ | ||||
| 	fpriv->minor->master = drm_master_create(fpriv->minor); | ||||
| 	if (!fpriv->minor->master) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	/* take another reference for the copy in the local file priv */ | ||||
| 	old_master = fpriv->master; | ||||
| 	fpriv->master = drm_master_get(fpriv->minor->master); | ||||
| 
 | ||||
| 	if (dev->driver->master_create) { | ||||
| 		ret = dev->driver->master_create(dev, fpriv->master); | ||||
| 		if (ret) | ||||
| 			goto out_err; | ||||
| 	} | ||||
| 	if (dev->driver->master_set) { | ||||
| 		ret = dev->driver->master_set(dev, fpriv, true); | ||||
| 		if (ret) | ||||
| 			goto out_err; | ||||
| 	} | ||||
| 
 | ||||
| 	fpriv->is_master = 1; | ||||
| 	fpriv->allowed_master = 1; | ||||
| 	fpriv->authenticated = 1; | ||||
| 	if (old_master) | ||||
| 		drm_master_put(&old_master); | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| out_err: | ||||
| 	/* drop both references and restore old master on failure */ | ||||
| 	drm_master_put(&fpriv->minor->master); | ||||
| 	drm_master_put(&fpriv->master); | ||||
| 	fpriv->master = old_master; | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Called whenever a process opens /dev/drm. | ||||
|  * | ||||
| @ -191,35 +245,9 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor) | ||||
| 	mutex_lock(&dev->master_mutex); | ||||
| 	if (drm_is_primary_client(priv) && !priv->minor->master) { | ||||
| 		/* create a new master */ | ||||
| 		priv->minor->master = drm_master_create(priv->minor); | ||||
| 		if (!priv->minor->master) { | ||||
| 			ret = -ENOMEM; | ||||
| 		ret = drm_new_set_master(dev, priv); | ||||
| 		if (ret) | ||||
| 			goto out_close; | ||||
| 		} | ||||
| 
 | ||||
| 		priv->is_master = 1; | ||||
| 		/* take another reference for the copy in the local file priv */ | ||||
| 		priv->master = drm_master_get(priv->minor->master); | ||||
| 		priv->authenticated = 1; | ||||
| 
 | ||||
| 		if (dev->driver->master_create) { | ||||
| 			ret = dev->driver->master_create(dev, priv->master); | ||||
| 			if (ret) { | ||||
| 				/* drop both references if this fails */ | ||||
| 				drm_master_put(&priv->minor->master); | ||||
| 				drm_master_put(&priv->master); | ||||
| 				goto out_close; | ||||
| 			} | ||||
| 		} | ||||
| 		if (dev->driver->master_set) { | ||||
| 			ret = dev->driver->master_set(dev, priv, true); | ||||
| 			if (ret) { | ||||
| 				/* drop both references if this fails */ | ||||
| 				drm_master_put(&priv->minor->master); | ||||
| 				drm_master_put(&priv->master); | ||||
| 				goto out_close; | ||||
| 			} | ||||
| 		} | ||||
| 	} else if (drm_is_primary_client(priv)) { | ||||
| 		/* get a reference to the master */ | ||||
| 		priv->master = drm_master_get(priv->minor->master); | ||||
|  | ||||
| @ -980,7 +980,8 @@ static void send_vblank_event(struct drm_device *dev, | ||||
| 		struct drm_pending_vblank_event *e, | ||||
| 		unsigned long seq, struct timeval *now) | ||||
| { | ||||
| 	WARN_ON_SMP(!spin_is_locked(&dev->event_lock)); | ||||
| 	assert_spin_locked(&dev->event_lock); | ||||
| 
 | ||||
| 	e->event.sequence = seq; | ||||
| 	e->event.tv_sec = now->tv_sec; | ||||
| 	e->event.tv_usec = now->tv_usec; | ||||
| @ -992,6 +993,57 @@ static void send_vblank_event(struct drm_device *dev, | ||||
| 					 e->event.sequence); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * drm_arm_vblank_event - arm vblank event after pageflip | ||||
|  * @dev: DRM device | ||||
|  * @pipe: CRTC index | ||||
|  * @e: the event to prepare to send | ||||
|  * | ||||
|  * A lot of drivers need to generate vblank events for the very next vblank | ||||
|  * interrupt. For example when the page flip interrupt happens when the page | ||||
|  * flip gets armed, but not when it actually executes within the next vblank | ||||
|  * period. This helper function implements exactly the required vblank arming | ||||
|  * behaviour. | ||||
|  * | ||||
|  * Caller must hold event lock. Caller must also hold a vblank reference for | ||||
|  * the event @e, which will be dropped when the next vblank arrives. | ||||
|  * | ||||
|  * This is the legacy version of drm_crtc_arm_vblank_event(). | ||||
|  */ | ||||
| void drm_arm_vblank_event(struct drm_device *dev, unsigned int pipe, | ||||
| 			  struct drm_pending_vblank_event *e) | ||||
| { | ||||
| 	assert_spin_locked(&dev->event_lock); | ||||
| 
 | ||||
| 	e->pipe = pipe; | ||||
| 	e->event.sequence = drm_vblank_count(dev, pipe); | ||||
| 	list_add_tail(&e->base.link, &dev->vblank_event_list); | ||||
| } | ||||
| EXPORT_SYMBOL(drm_arm_vblank_event); | ||||
| 
 | ||||
| /**
 | ||||
|  * drm_crtc_arm_vblank_event - arm vblank event after pageflip | ||||
|  * @crtc: the source CRTC of the vblank event | ||||
|  * @e: the event to send | ||||
|  * | ||||
|  * A lot of drivers need to generate vblank events for the very next vblank | ||||
|  * interrupt. For example when the page flip interrupt happens when the page | ||||
|  * flip gets armed, but not when it actually executes within the next vblank | ||||
|  * period. This helper function implements exactly the required vblank arming | ||||
|  * behaviour. | ||||
|  * | ||||
|  * Caller must hold event lock. Caller must also hold a vblank reference for | ||||
|  * the event @e, which will be dropped when the next vblank arrives. | ||||
|  * | ||||
|  * This is the native KMS version of drm_arm_vblank_event(). | ||||
|  */ | ||||
| void drm_crtc_arm_vblank_event(struct drm_crtc *crtc, | ||||
| 			       struct drm_pending_vblank_event *e) | ||||
| { | ||||
| 	drm_arm_vblank_event(crtc->dev, drm_crtc_index(crtc), e); | ||||
| } | ||||
| EXPORT_SYMBOL(drm_crtc_arm_vblank_event); | ||||
| 
 | ||||
| /**
 | ||||
|  * drm_send_vblank_event - helper to send vblank event after pageflip | ||||
|  * @dev: DRM device | ||||
|  | ||||
| @ -1210,8 +1210,16 @@ int __i915_wait_request(struct drm_i915_gem_request *req, | ||||
| 	if (i915_gem_request_completed(req, true)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	timeout_expire = timeout ? | ||||
| 		jiffies + nsecs_to_jiffies_timeout((u64)*timeout) : 0; | ||||
| 	timeout_expire = 0; | ||||
| 	if (timeout) { | ||||
| 		if (WARN_ON(*timeout < 0)) | ||||
| 			return -EINVAL; | ||||
| 
 | ||||
| 		if (*timeout == 0) | ||||
| 			return -ETIME; | ||||
| 
 | ||||
| 		timeout_expire = jiffies + nsecs_to_jiffies_timeout(*timeout); | ||||
| 	} | ||||
| 
 | ||||
| 	if (INTEL_INFO(dev_priv)->gen >= 6) | ||||
| 		gen6_rps_boost(dev_priv, rps, req->emitted_jiffies); | ||||
|  | ||||
| @ -642,11 +642,10 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) | ||||
| 		} | ||||
| 
 | ||||
| 		/* check for L-shaped memory aka modified enhanced addressing */ | ||||
| 		if (IS_GEN4(dev)) { | ||||
| 			uint32_t ddc2 = I915_READ(DCC2); | ||||
| 
 | ||||
| 			if (!(ddc2 & DCC2_MODIFIED_ENHANCED_DISABLE)) | ||||
| 				dev_priv->quirks |= QUIRK_PIN_SWIZZLED_PAGES; | ||||
| 		if (IS_GEN4(dev) && | ||||
| 		    !(I915_READ(DCC2) & DCC2_MODIFIED_ENHANCED_DISABLE)) { | ||||
| 			swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; | ||||
| 			swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; | ||||
| 		} | ||||
| 
 | ||||
| 		if (dcc == 0xffffffff) { | ||||
| @ -675,16 +674,35 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) | ||||
| 		 * matching, which was the case for the swizzling required in | ||||
| 		 * the table above, or from the 1-ch value being less than | ||||
| 		 * the minimum size of a rank. | ||||
| 		 * | ||||
| 		 * Reports indicate that the swizzling actually | ||||
| 		 * varies depending upon page placement inside the | ||||
| 		 * channels, i.e. we see swizzled pages where the | ||||
| 		 * banks of memory are paired and unswizzled on the | ||||
| 		 * uneven portion, so leave that as unknown. | ||||
| 		 */ | ||||
| 		if (I915_READ16(C0DRB3) != I915_READ16(C1DRB3)) { | ||||
| 			swizzle_x = I915_BIT_6_SWIZZLE_NONE; | ||||
| 			swizzle_y = I915_BIT_6_SWIZZLE_NONE; | ||||
| 		} else { | ||||
| 		if (I915_READ16(C0DRB3) == I915_READ16(C1DRB3)) { | ||||
| 			swizzle_x = I915_BIT_6_SWIZZLE_9_10; | ||||
| 			swizzle_y = I915_BIT_6_SWIZZLE_9; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (swizzle_x == I915_BIT_6_SWIZZLE_UNKNOWN || | ||||
| 	    swizzle_y == I915_BIT_6_SWIZZLE_UNKNOWN) { | ||||
| 		/* Userspace likes to explode if it sees unknown swizzling,
 | ||||
| 		 * so lie. We will finish the lie when reporting through | ||||
| 		 * the get-tiling-ioctl by reporting the physical swizzle | ||||
| 		 * mode as unknown instead. | ||||
| 		 * | ||||
| 		 * As we don't strictly know what the swizzling is, it may be | ||||
| 		 * bit17 dependent, and so we need to also prevent the pages | ||||
| 		 * from being moved. | ||||
| 		 */ | ||||
| 		dev_priv->quirks |= QUIRK_PIN_SWIZZLED_PAGES; | ||||
| 		swizzle_x = I915_BIT_6_SWIZZLE_NONE; | ||||
| 		swizzle_y = I915_BIT_6_SWIZZLE_NONE; | ||||
| 	} | ||||
| 
 | ||||
| 	dev_priv->mm.bit_6_swizzle_x = swizzle_x; | ||||
| 	dev_priv->mm.bit_6_swizzle_y = swizzle_y; | ||||
| } | ||||
|  | ||||
| @ -12582,7 +12582,6 @@ intel_pipe_config_compare(struct drm_device *dev, | ||||
| 	if (INTEL_INFO(dev)->gen < 8) { | ||||
| 		PIPE_CONF_CHECK_M_N(dp_m_n); | ||||
| 
 | ||||
| 		PIPE_CONF_CHECK_I(has_drrs); | ||||
| 		if (current_config->has_drrs) | ||||
| 			PIPE_CONF_CHECK_M_N(dp_m2_n2); | ||||
| 	} else | ||||
|  | ||||
| @ -4962,7 +4962,8 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd) | ||||
| 	enum intel_display_power_domain power_domain; | ||||
| 	enum irqreturn ret = IRQ_NONE; | ||||
| 
 | ||||
| 	if (intel_dig_port->base.type != INTEL_OUTPUT_EDP) | ||||
| 	if (intel_dig_port->base.type != INTEL_OUTPUT_EDP && | ||||
| 	    intel_dig_port->base.type != INTEL_OUTPUT_HDMI) | ||||
| 		intel_dig_port->base.type = INTEL_OUTPUT_DISPLAYPORT; | ||||
| 
 | ||||
| 	if (long_hpd && intel_dig_port->base.type == INTEL_OUTPUT_EDP) { | ||||
|  | ||||
| @ -64,8 +64,7 @@ static void imx_drm_driver_lastclose(struct drm_device *drm) | ||||
| { | ||||
| 	struct imx_drm_device *imxdrm = drm->dev_private; | ||||
| 
 | ||||
| 	if (imxdrm->fbhelper) | ||||
| 		drm_fbdev_cma_restore_mode(imxdrm->fbhelper); | ||||
| 	drm_fbdev_cma_restore_mode(imxdrm->fbhelper); | ||||
| } | ||||
| 
 | ||||
| static int imx_drm_driver_unload(struct drm_device *drm) | ||||
| @ -334,7 +333,7 @@ err_kms: | ||||
|  * imx_drm_add_crtc - add a new crtc | ||||
|  */ | ||||
| int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, | ||||
| 		struct imx_drm_crtc **new_crtc, | ||||
| 		struct imx_drm_crtc **new_crtc, struct drm_plane *primary_plane, | ||||
| 		const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs, | ||||
| 		struct device_node *port) | ||||
| { | ||||
| @ -373,7 +372,7 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, | ||||
| 	drm_crtc_helper_add(crtc, | ||||
| 			imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs); | ||||
| 
 | ||||
| 	drm_crtc_init(drm, crtc, | ||||
| 	drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL, | ||||
| 			imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs); | ||||
| 
 | ||||
| 	return 0; | ||||
|  | ||||
| @ -9,6 +9,7 @@ struct drm_display_mode; | ||||
| struct drm_encoder; | ||||
| struct drm_fbdev_cma; | ||||
| struct drm_framebuffer; | ||||
| struct drm_plane; | ||||
| struct imx_drm_crtc; | ||||
| struct platform_device; | ||||
| 
 | ||||
| @ -24,7 +25,7 @@ struct imx_drm_crtc_helper_funcs { | ||||
| }; | ||||
| 
 | ||||
| int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, | ||||
| 		struct imx_drm_crtc **new_crtc, | ||||
| 		struct imx_drm_crtc **new_crtc, struct drm_plane *primary_plane, | ||||
| 		const struct imx_drm_crtc_helper_funcs *imx_helper_funcs, | ||||
| 		struct device_node *port); | ||||
| int imx_drm_remove_crtc(struct imx_drm_crtc *); | ||||
|  | ||||
| @ -721,6 +721,7 @@ static const struct of_device_id imx_tve_dt_ids[] = { | ||||
| 	{ .compatible = "fsl,imx53-tve", }, | ||||
| 	{ /* sentinel */ } | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(of, imx_tve_dt_ids); | ||||
| 
 | ||||
| static struct platform_driver imx_tve_driver = { | ||||
| 	.probe		= imx_tve_probe, | ||||
|  | ||||
| @ -212,7 +212,8 @@ static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc) | ||||
| 
 | ||||
| 	spin_lock_irqsave(&drm->event_lock, flags); | ||||
| 	if (ipu_crtc->page_flip_event) | ||||
| 		drm_send_vblank_event(drm, -1, ipu_crtc->page_flip_event); | ||||
| 		drm_crtc_send_vblank_event(&ipu_crtc->base, | ||||
| 					   ipu_crtc->page_flip_event); | ||||
| 	ipu_crtc->page_flip_event = NULL; | ||||
| 	imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc); | ||||
| 	spin_unlock_irqrestore(&drm->event_lock, flags); | ||||
| @ -349,7 +350,6 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, | ||||
| 	struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); | ||||
| 	int dp = -EINVAL; | ||||
| 	int ret; | ||||
| 	int id; | ||||
| 
 | ||||
| 	ret = ipu_get_resources(ipu_crtc, pdata); | ||||
| 	if (ret) { | ||||
| @ -358,18 +358,23 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	if (pdata->dp >= 0) | ||||
| 		dp = IPU_DP_FLOW_SYNC_BG; | ||||
| 	ipu_crtc->plane[0] = ipu_plane_init(drm, ipu, pdata->dma[0], dp, 0, | ||||
| 					    DRM_PLANE_TYPE_PRIMARY); | ||||
| 	if (IS_ERR(ipu_crtc->plane[0])) { | ||||
| 		ret = PTR_ERR(ipu_crtc->plane[0]); | ||||
| 		goto err_put_resources; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc, | ||||
| 			&ipu_crtc_helper_funcs, ipu_crtc->dev->of_node); | ||||
| 			&ipu_crtc->plane[0]->base, &ipu_crtc_helper_funcs, | ||||
| 			ipu_crtc->dev->of_node); | ||||
| 	if (ret) { | ||||
| 		dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret); | ||||
| 		goto err_put_resources; | ||||
| 	} | ||||
| 
 | ||||
| 	if (pdata->dp >= 0) | ||||
| 		dp = IPU_DP_FLOW_SYNC_BG; | ||||
| 	id = imx_drm_crtc_id(ipu_crtc->imx_crtc); | ||||
| 	ipu_crtc->plane[0] = ipu_plane_init(ipu_crtc->base.dev, ipu, | ||||
| 					    pdata->dma[0], dp, BIT(id), true); | ||||
| 	ret = ipu_plane_get_resources(ipu_crtc->plane[0]); | ||||
| 	if (ret) { | ||||
| 		dev_err(ipu_crtc->dev, "getting plane 0 resources failed with %d.\n", | ||||
| @ -379,10 +384,10 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, | ||||
| 
 | ||||
| 	/* If this crtc is using the DP, add an overlay plane */ | ||||
| 	if (pdata->dp >= 0 && pdata->dma[1] > 0) { | ||||
| 		ipu_crtc->plane[1] = ipu_plane_init(ipu_crtc->base.dev, ipu, | ||||
| 						    pdata->dma[1], | ||||
| 						    IPU_DP_FLOW_SYNC_FG, | ||||
| 						    BIT(id), false); | ||||
| 		ipu_crtc->plane[1] = ipu_plane_init(drm, ipu, pdata->dma[1], | ||||
| 						IPU_DP_FLOW_SYNC_FG, | ||||
| 						drm_crtc_mask(&ipu_crtc->base), | ||||
| 						DRM_PLANE_TYPE_OVERLAY); | ||||
| 		if (IS_ERR(ipu_crtc->plane[1])) | ||||
| 			ipu_crtc->plane[1] = NULL; | ||||
| 	} | ||||
| @ -407,28 +412,6 @@ err_put_resources: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static struct device_node *ipu_drm_get_port_by_id(struct device_node *parent, | ||||
| 						  int port_id) | ||||
| { | ||||
| 	struct device_node *port; | ||||
| 	int id, ret; | ||||
| 
 | ||||
| 	port = of_get_child_by_name(parent, "port"); | ||||
| 	while (port) { | ||||
| 		ret = of_property_read_u32(port, "reg", &id); | ||||
| 		if (!ret && id == port_id) | ||||
| 			return port; | ||||
| 
 | ||||
| 		do { | ||||
| 			port = of_get_next_child(parent, port); | ||||
| 			if (!port) | ||||
| 				return NULL; | ||||
| 		} while (of_node_cmp(port->name, "port")); | ||||
| 	} | ||||
| 
 | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static int ipu_drm_bind(struct device *dev, struct device *master, void *data) | ||||
| { | ||||
| 	struct ipu_client_platformdata *pdata = dev->platform_data; | ||||
| @ -470,23 +453,11 @@ static const struct component_ops ipu_crtc_ops = { | ||||
| static int ipu_drm_probe(struct platform_device *pdev) | ||||
| { | ||||
| 	struct device *dev = &pdev->dev; | ||||
| 	struct ipu_client_platformdata *pdata = dev->platform_data; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (!dev->platform_data) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	if (!dev->of_node) { | ||||
| 		/* Associate crtc device with the corresponding DI port node */ | ||||
| 		dev->of_node = ipu_drm_get_port_by_id(dev->parent->of_node, | ||||
| 						      pdata->di + 2); | ||||
| 		if (!dev->of_node) { | ||||
| 			dev_err(dev, "missing port@%d node in %s\n", | ||||
| 				pdata->di + 2, dev->parent->of_node->full_name); | ||||
| 			return -ENODEV; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
|  | ||||
| @ -381,7 +381,7 @@ static struct drm_plane_funcs ipu_plane_funcs = { | ||||
| 
 | ||||
| struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, | ||||
| 				 int dma, int dp, unsigned int possible_crtcs, | ||||
| 				 bool priv) | ||||
| 				 enum drm_plane_type type) | ||||
| { | ||||
| 	struct ipu_plane *ipu_plane; | ||||
| 	int ret; | ||||
| @ -399,10 +399,9 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, | ||||
| 	ipu_plane->dma = dma; | ||||
| 	ipu_plane->dp_flow = dp; | ||||
| 
 | ||||
| 	ret = drm_plane_init(dev, &ipu_plane->base, possible_crtcs, | ||||
| 			     &ipu_plane_funcs, ipu_plane_formats, | ||||
| 			     ARRAY_SIZE(ipu_plane_formats), | ||||
| 			     priv); | ||||
| 	ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs, | ||||
| 				       &ipu_plane_funcs, ipu_plane_formats, | ||||
| 				       ARRAY_SIZE(ipu_plane_formats), type); | ||||
| 	if (ret) { | ||||
| 		DRM_ERROR("failed to initialize plane\n"); | ||||
| 		kfree(ipu_plane); | ||||
|  | ||||
| @ -34,7 +34,7 @@ struct ipu_plane { | ||||
| 
 | ||||
| struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, | ||||
| 				 int dma, int dp, unsigned int possible_crtcs, | ||||
| 				 bool priv); | ||||
| 				 enum drm_plane_type type); | ||||
| 
 | ||||
| /* Init IDMAC, DMFC, DP */ | ||||
| int ipu_plane_mode_set(struct ipu_plane *plane, struct drm_crtc *crtc, | ||||
|  | ||||
| @ -54,7 +54,11 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector) | ||||
| 
 | ||||
| 	if (imxpd->panel && imxpd->panel->funcs && | ||||
| 	    imxpd->panel->funcs->get_modes) { | ||||
| 		struct drm_display_info *di = &connector->display_info; | ||||
| 
 | ||||
| 		num_modes = imxpd->panel->funcs->get_modes(imxpd->panel); | ||||
| 		if (!imxpd->bus_format && di->num_bus_formats) | ||||
| 			imxpd->bus_format = di->bus_formats[0]; | ||||
| 		if (num_modes > 0) | ||||
| 			return num_modes; | ||||
| 	} | ||||
|  | ||||
| @ -829,7 +829,6 @@ nouveau_finish_page_flip(struct nouveau_channel *chan, | ||||
| 	struct drm_device *dev = drm->dev; | ||||
| 	struct nouveau_page_flip_state *s; | ||||
| 	unsigned long flags; | ||||
| 	int crtcid = -1; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&dev->event_lock, flags); | ||||
| 
 | ||||
| @ -841,15 +840,19 @@ nouveau_finish_page_flip(struct nouveau_channel *chan, | ||||
| 
 | ||||
| 	s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head); | ||||
| 	if (s->event) { | ||||
| 		/* Vblank timestamps/counts are only correct on >= NV-50 */ | ||||
| 		if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) | ||||
| 			crtcid = s->crtc; | ||||
| 		if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) { | ||||
| 			drm_arm_vblank_event(dev, s->crtc, s->event); | ||||
| 		} else { | ||||
| 			drm_send_vblank_event(dev, s->crtc, s->event); | ||||
| 
 | ||||
| 		drm_send_vblank_event(dev, crtcid, s->event); | ||||
| 			/* Give up ownership of vblank for page-flipped crtc */ | ||||
| 			drm_vblank_put(dev, s->crtc); | ||||
| 		} | ||||
| 	} | ||||
| 	else { | ||||
| 		/* Give up ownership of vblank for page-flipped crtc */ | ||||
| 		drm_vblank_put(dev, s->crtc); | ||||
| 	} | ||||
| 
 | ||||
| 	/* Give up ownership of vblank for page-flipped crtc */ | ||||
| 	drm_vblank_put(dev, s->crtc); | ||||
| 
 | ||||
| 	list_del(&s->head); | ||||
| 	if (ps) | ||||
|  | ||||
| @ -8472,7 +8472,7 @@ restart_ih: | ||||
| 	if (queue_dp) | ||||
| 		schedule_work(&rdev->dp_work); | ||||
| 	if (queue_hotplug) | ||||
| 		schedule_work(&rdev->hotplug_work); | ||||
| 		schedule_delayed_work(&rdev->hotplug_work, 0); | ||||
| 	if (queue_reset) { | ||||
| 		rdev->needs_reset = true; | ||||
| 		wake_up_all(&rdev->fence_queue); | ||||
| @ -9630,6 +9630,9 @@ static void dce8_program_watermarks(struct radeon_device *rdev, | ||||
| 		    (rdev->disp_priority == 2)) { | ||||
| 			DRM_DEBUG_KMS("force priority to high\n"); | ||||
| 		} | ||||
| 
 | ||||
| 		/* Save number of lines the linebuffer leads before the scanout */ | ||||
| 		radeon_crtc->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay); | ||||
| 	} | ||||
| 
 | ||||
| 	/* select wm A */ | ||||
|  | ||||
| @ -2372,6 +2372,9 @@ static void evergreen_program_watermarks(struct radeon_device *rdev, | ||||
| 		c.full = dfixed_div(c, a); | ||||
| 		priority_b_mark = dfixed_trunc(c); | ||||
| 		priority_b_cnt |= priority_b_mark & PRIORITY_MARK_MASK; | ||||
| 
 | ||||
| 		/* Save number of lines the linebuffer leads before the scanout */ | ||||
| 		radeon_crtc->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay); | ||||
| 	} | ||||
| 
 | ||||
| 	/* select wm A */ | ||||
| @ -5344,7 +5347,7 @@ restart_ih: | ||||
| 	if (queue_dp) | ||||
| 		schedule_work(&rdev->dp_work); | ||||
| 	if (queue_hotplug) | ||||
| 		schedule_work(&rdev->hotplug_work); | ||||
| 		schedule_delayed_work(&rdev->hotplug_work, 0); | ||||
| 	if (queue_hdmi) | ||||
| 		schedule_work(&rdev->audio_work); | ||||
| 	if (queue_thermal && rdev->pm.dpm_enabled) | ||||
|  | ||||
| @ -806,7 +806,7 @@ int r100_irq_process(struct radeon_device *rdev) | ||||
| 		status = r100_irq_ack(rdev); | ||||
| 	} | ||||
| 	if (queue_hotplug) | ||||
| 		schedule_work(&rdev->hotplug_work); | ||||
| 		schedule_delayed_work(&rdev->hotplug_work, 0); | ||||
| 	if (rdev->msi_enabled) { | ||||
| 		switch (rdev->family) { | ||||
| 		case CHIP_RS400: | ||||
| @ -3217,6 +3217,9 @@ void r100_bandwidth_update(struct radeon_device *rdev) | ||||
| 	uint32_t pixel_bytes1 = 0; | ||||
| 	uint32_t pixel_bytes2 = 0; | ||||
| 
 | ||||
| 	/* Guess line buffer size to be 8192 pixels */ | ||||
| 	u32 lb_size = 8192; | ||||
| 
 | ||||
| 	if (!rdev->mode_info.mode_config_initialized) | ||||
| 		return; | ||||
| 
 | ||||
| @ -3631,6 +3634,13 @@ void r100_bandwidth_update(struct radeon_device *rdev) | ||||
| 		DRM_DEBUG_KMS("GRPH2_BUFFER_CNTL from to %x\n", | ||||
| 			  (unsigned int)RREG32(RADEON_GRPH2_BUFFER_CNTL)); | ||||
| 	} | ||||
| 
 | ||||
| 	/* Save number of lines the linebuffer leads before the scanout */ | ||||
| 	if (mode1) | ||||
| 	    rdev->mode_info.crtcs[0]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode1->crtc_hdisplay); | ||||
| 
 | ||||
| 	if (mode2) | ||||
| 	    rdev->mode_info.crtcs[1]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode2->crtc_hdisplay); | ||||
| } | ||||
| 
 | ||||
| int r100_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) | ||||
|  | ||||
| @ -4276,7 +4276,7 @@ restart_ih: | ||||
| 		WREG32(IH_RB_RPTR, rptr); | ||||
| 	} | ||||
| 	if (queue_hotplug) | ||||
| 		schedule_work(&rdev->hotplug_work); | ||||
| 		schedule_delayed_work(&rdev->hotplug_work, 0); | ||||
| 	if (queue_hdmi) | ||||
| 		schedule_work(&rdev->audio_work); | ||||
| 	if (queue_thermal && rdev->pm.dpm_enabled) | ||||
|  | ||||
| @ -2414,7 +2414,7 @@ struct radeon_device { | ||||
| 	struct r600_ih ih; /* r6/700 interrupt ring */ | ||||
| 	struct radeon_rlc rlc; | ||||
| 	struct radeon_mec mec; | ||||
| 	struct work_struct hotplug_work; | ||||
| 	struct delayed_work hotplug_work; | ||||
| 	struct work_struct dp_work; | ||||
| 	struct work_struct audio_work; | ||||
| 	int num_crtc; /* number of crtcs */ | ||||
|  | ||||
| @ -54,6 +54,9 @@ static struct radeon_agpmode_quirk radeon_agpmode_quirk_list[] = { | ||||
| 	/* Intel 82855PM host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (lp #195051) */ | ||||
| 	{ PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4e50, | ||||
| 		PCI_VENDOR_ID_IBM, 0x0550, 1}, | ||||
| 	/* Intel 82855PM host bridge / RV250/M9 GL [Mobility FireGL 9000/Radeon 9000] needs AGPMode 1 (Thinkpad T40p) */ | ||||
| 	{ PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4c66, | ||||
| 		PCI_VENDOR_ID_IBM, 0x054d, 1}, | ||||
| 	/* Intel 82855PM host bridge / Mobility M7 needs AGPMode 1 */ | ||||
| 	{ PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4c57, | ||||
| 		PCI_VENDOR_ID_IBM, 0x0530, 1}, | ||||
|  | ||||
| @ -1234,13 +1234,32 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) | ||||
| 	if (r < 0) | ||||
| 		return connector_status_disconnected; | ||||
| 
 | ||||
| 	if (radeon_connector->detected_hpd_without_ddc) { | ||||
| 		force = true; | ||||
| 		radeon_connector->detected_hpd_without_ddc = false; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!force && radeon_check_hpd_status_unchanged(connector)) { | ||||
| 		ret = connector->status; | ||||
| 		goto exit; | ||||
| 	} | ||||
| 
 | ||||
| 	if (radeon_connector->ddc_bus) | ||||
| 	if (radeon_connector->ddc_bus) { | ||||
| 		dret = radeon_ddc_probe(radeon_connector, false); | ||||
| 
 | ||||
| 		/* Sometimes the pins required for the DDC probe on DVI
 | ||||
| 		 * connectors don't make contact at the same time that the ones | ||||
| 		 * for HPD do. If the DDC probe fails even though we had an HPD | ||||
| 		 * signal, try again later */ | ||||
| 		if (!dret && !force && | ||||
| 		    connector->status != connector_status_connected) { | ||||
| 			DRM_DEBUG_KMS("hpd detected without ddc, retrying in 1 second\n"); | ||||
| 			radeon_connector->detected_hpd_without_ddc = true; | ||||
| 			schedule_delayed_work(&rdev->hotplug_work, | ||||
| 					      msecs_to_jiffies(1000)); | ||||
| 			goto exit; | ||||
| 		} | ||||
| 	} | ||||
| 	if (dret) { | ||||
| 		radeon_connector->detected_by_load = false; | ||||
| 		radeon_connector_free_edid(connector); | ||||
|  | ||||
| @ -322,7 +322,9 @@ void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id) | ||||
| 	 * to complete in this vblank? | ||||
| 	 */ | ||||
| 	if (update_pending && | ||||
| 	    (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id, 0, | ||||
| 	    (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, | ||||
| 							       crtc_id, | ||||
| 							       USE_REAL_VBLANKSTART, | ||||
| 							       &vpos, &hpos, NULL, NULL, | ||||
| 							       &rdev->mode_info.crtcs[crtc_id]->base.hwmode)) && | ||||
| 	    ((vpos >= (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100) || | ||||
| @ -401,6 +403,8 @@ static void radeon_flip_work_func(struct work_struct *__work) | ||||
| 	struct drm_crtc *crtc = &radeon_crtc->base; | ||||
| 	unsigned long flags; | ||||
| 	int r; | ||||
| 	int vpos, hpos, stat, min_udelay; | ||||
| 	struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id]; | ||||
| 
 | ||||
|         down_read(&rdev->exclusive_lock); | ||||
| 	if (work->fence) { | ||||
| @ -437,6 +441,41 @@ static void radeon_flip_work_func(struct work_struct *__work) | ||||
| 	/* set the proper interrupt */ | ||||
| 	radeon_irq_kms_pflip_irq_get(rdev, radeon_crtc->crtc_id); | ||||
| 
 | ||||
| 	/* If this happens to execute within the "virtually extended" vblank
 | ||||
| 	 * interval before the start of the real vblank interval then it needs | ||||
| 	 * to delay programming the mmio flip until the real vblank is entered. | ||||
| 	 * This prevents completing a flip too early due to the way we fudge | ||||
| 	 * our vblank counter and vblank timestamps in order to work around the | ||||
| 	 * problem that the hw fires vblank interrupts before actual start of | ||||
| 	 * vblank (when line buffer refilling is done for a frame). It | ||||
| 	 * complements the fudging logic in radeon_get_crtc_scanoutpos() for | ||||
| 	 * timestamping and radeon_get_vblank_counter_kms() for vblank counts. | ||||
| 	 * | ||||
| 	 * In practice this won't execute very often unless on very fast | ||||
| 	 * machines because the time window for this to happen is very small. | ||||
| 	 */ | ||||
| 	for (;;) { | ||||
| 		/* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank
 | ||||
| 		 * start in hpos, and to the "fudged earlier" vblank start in | ||||
| 		 * vpos. | ||||
| 		 */ | ||||
| 		stat = radeon_get_crtc_scanoutpos(rdev->ddev, work->crtc_id, | ||||
| 						  GET_DISTANCE_TO_VBLANKSTART, | ||||
| 						  &vpos, &hpos, NULL, NULL, | ||||
| 						  &crtc->hwmode); | ||||
| 
 | ||||
| 		if ((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) != | ||||
| 		    (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE) || | ||||
| 		    !(vpos >= 0 && hpos <= 0)) | ||||
| 			break; | ||||
| 
 | ||||
| 		/* Sleep at least until estimated real start of hw vblank */ | ||||
| 		spin_unlock_irqrestore(&crtc->dev->event_lock, flags); | ||||
| 		min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5); | ||||
| 		usleep_range(min_udelay, 2 * min_udelay); | ||||
| 		spin_lock_irqsave(&crtc->dev->event_lock, flags); | ||||
| 	}; | ||||
| 
 | ||||
| 	/* do the flip (mmio) */ | ||||
| 	radeon_page_flip(rdev, radeon_crtc->crtc_id, work->base); | ||||
| 
 | ||||
| @ -1768,6 +1807,15 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, | ||||
|  * \param dev Device to query. | ||||
|  * \param crtc Crtc to query. | ||||
|  * \param flags Flags from caller (DRM_CALLED_FROM_VBLIRQ or 0). | ||||
|  *              For driver internal use only also supports these flags: | ||||
|  * | ||||
|  *              USE_REAL_VBLANKSTART to use the real start of vblank instead | ||||
|  *              of a fudged earlier start of vblank. | ||||
|  * | ||||
|  *              GET_DISTANCE_TO_VBLANKSTART to return distance to the | ||||
|  *              fudged earlier start of vblank in *vpos and the distance | ||||
|  *              to true start of vblank in *hpos. | ||||
|  * | ||||
|  * \param *vpos Location where vertical scanout position should be stored. | ||||
|  * \param *hpos Location where horizontal scanout position should go. | ||||
|  * \param *stime Target location for timestamp taken immediately before | ||||
| @ -1911,10 +1959,40 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, | ||||
| 		vbl_end = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Called from driver internal vblank counter query code? */ | ||||
| 	if (flags & GET_DISTANCE_TO_VBLANKSTART) { | ||||
| 	    /* Caller wants distance from real vbl_start in *hpos */ | ||||
| 	    *hpos = *vpos - vbl_start; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Fudge vblank to start a few scanlines earlier to handle the
 | ||||
| 	 * problem that vblank irqs fire a few scanlines before start | ||||
| 	 * of vblank. Some driver internal callers need the true vblank | ||||
| 	 * start to be used and signal this via the USE_REAL_VBLANKSTART flag. | ||||
| 	 * | ||||
| 	 * The cause of the "early" vblank irq is that the irq is triggered | ||||
| 	 * by the line buffer logic when the line buffer read position enters | ||||
| 	 * the vblank, whereas our crtc scanout position naturally lags the | ||||
| 	 * line buffer read position. | ||||
| 	 */ | ||||
| 	if (!(flags & USE_REAL_VBLANKSTART)) | ||||
| 		vbl_start -= rdev->mode_info.crtcs[pipe]->lb_vblank_lead_lines; | ||||
| 
 | ||||
| 	/* Test scanout position against vblank region. */ | ||||
| 	if ((*vpos < vbl_start) && (*vpos >= vbl_end)) | ||||
| 		in_vbl = false; | ||||
| 
 | ||||
| 	/* In vblank? */ | ||||
| 	if (in_vbl) | ||||
| 	    ret |= DRM_SCANOUTPOS_IN_VBLANK; | ||||
| 
 | ||||
| 	/* Called from driver internal vblank counter query code? */ | ||||
| 	if (flags & GET_DISTANCE_TO_VBLANKSTART) { | ||||
| 		/* Caller wants distance from fudged earlier vbl_start */ | ||||
| 		*vpos -= vbl_start; | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Check if inside vblank area and apply corrective offsets:
 | ||||
| 	 * vpos will then be >=0 in video scanout area, but negative | ||||
| 	 * within vblank area, counting down the number of lines until | ||||
| @ -1930,31 +2008,5 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, | ||||
| 	/* Correct for shifted end of vbl at vbl_end. */ | ||||
| 	*vpos = *vpos - vbl_end; | ||||
| 
 | ||||
| 	/* In vblank? */ | ||||
| 	if (in_vbl) | ||||
| 		ret |= DRM_SCANOUTPOS_IN_VBLANK; | ||||
| 
 | ||||
| 	/* Is vpos outside nominal vblank area, but less than
 | ||||
| 	 * 1/100 of a frame height away from start of vblank? | ||||
| 	 * If so, assume this isn't a massively delayed vblank | ||||
| 	 * interrupt, but a vblank interrupt that fired a few | ||||
| 	 * microseconds before true start of vblank. Compensate | ||||
| 	 * by adding a full frame duration to the final timestamp. | ||||
| 	 * Happens, e.g., on ATI R500, R600. | ||||
| 	 * | ||||
| 	 * We only do this if DRM_CALLED_FROM_VBLIRQ. | ||||
| 	 */ | ||||
| 	if ((flags & DRM_CALLED_FROM_VBLIRQ) && !in_vbl) { | ||||
| 		vbl_start = mode->crtc_vdisplay; | ||||
| 		vtotal = mode->crtc_vtotal; | ||||
| 
 | ||||
| 		if (vbl_start - *vpos < vtotal / 100) { | ||||
| 			*vpos -= vtotal; | ||||
| 
 | ||||
| 			/* Signal this correction as "applied". */ | ||||
| 			ret |= 0x8; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| @ -74,7 +74,7 @@ irqreturn_t radeon_driver_irq_handler_kms(int irq, void *arg) | ||||
| static void radeon_hotplug_work_func(struct work_struct *work) | ||||
| { | ||||
| 	struct radeon_device *rdev = container_of(work, struct radeon_device, | ||||
| 						  hotplug_work); | ||||
| 						  hotplug_work.work); | ||||
| 	struct drm_device *dev = rdev->ddev; | ||||
| 	struct drm_mode_config *mode_config = &dev->mode_config; | ||||
| 	struct drm_connector *connector; | ||||
| @ -302,7 +302,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func); | ||||
| 	INIT_DELAYED_WORK(&rdev->hotplug_work, radeon_hotplug_work_func); | ||||
| 	INIT_WORK(&rdev->dp_work, radeon_dp_work_func); | ||||
| 	INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi); | ||||
| 
 | ||||
| @ -310,7 +310,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev) | ||||
| 	r = drm_irq_install(rdev->ddev, rdev->ddev->pdev->irq); | ||||
| 	if (r) { | ||||
| 		rdev->irq.installed = false; | ||||
| 		flush_work(&rdev->hotplug_work); | ||||
| 		flush_delayed_work(&rdev->hotplug_work); | ||||
| 		return r; | ||||
| 	} | ||||
| 
 | ||||
| @ -333,7 +333,7 @@ void radeon_irq_kms_fini(struct radeon_device *rdev) | ||||
| 		rdev->irq.installed = false; | ||||
| 		if (rdev->msi_enabled) | ||||
| 			pci_disable_msi(rdev->pdev); | ||||
| 		flush_work(&rdev->hotplug_work); | ||||
| 		flush_delayed_work(&rdev->hotplug_work); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -755,6 +755,8 @@ void radeon_driver_preclose_kms(struct drm_device *dev, | ||||
|  */ | ||||
| u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc) | ||||
| { | ||||
| 	int vpos, hpos, stat; | ||||
| 	u32 count; | ||||
| 	struct radeon_device *rdev = dev->dev_private; | ||||
| 
 | ||||
| 	if (crtc < 0 || crtc >= rdev->num_crtc) { | ||||
| @ -762,7 +764,53 @@ u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc) | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	return radeon_get_vblank_counter(rdev, crtc); | ||||
| 	/* The hw increments its frame counter at start of vsync, not at start
 | ||||
| 	 * of vblank, as is required by DRM core vblank counter handling. | ||||
| 	 * Cook the hw count here to make it appear to the caller as if it | ||||
| 	 * incremented at start of vblank. We measure distance to start of | ||||
| 	 * vblank in vpos. vpos therefore will be >= 0 between start of vblank | ||||
| 	 * and start of vsync, so vpos >= 0 means to bump the hw frame counter | ||||
| 	 * result by 1 to give the proper appearance to caller. | ||||
| 	 */ | ||||
| 	if (rdev->mode_info.crtcs[crtc]) { | ||||
| 		/* Repeat readout if needed to provide stable result if
 | ||||
| 		 * we cross start of vsync during the queries. | ||||
| 		 */ | ||||
| 		do { | ||||
| 			count = radeon_get_vblank_counter(rdev, crtc); | ||||
| 			/* Ask radeon_get_crtc_scanoutpos to return vpos as
 | ||||
| 			 * distance to start of vblank, instead of regular | ||||
| 			 * vertical scanout pos. | ||||
| 			 */ | ||||
| 			stat = radeon_get_crtc_scanoutpos( | ||||
| 				dev, crtc, GET_DISTANCE_TO_VBLANKSTART, | ||||
| 				&vpos, &hpos, NULL, NULL, | ||||
| 				&rdev->mode_info.crtcs[crtc]->base.hwmode); | ||||
| 		} while (count != radeon_get_vblank_counter(rdev, crtc)); | ||||
| 
 | ||||
| 		if (((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) != | ||||
| 		    (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE))) { | ||||
| 			DRM_DEBUG_VBL("Query failed! stat %d\n", stat); | ||||
| 		} | ||||
| 		else { | ||||
| 			DRM_DEBUG_VBL("crtc %d: dist from vblank start %d\n", | ||||
| 				      crtc, vpos); | ||||
| 
 | ||||
| 			/* Bump counter if we are at >= leading edge of vblank,
 | ||||
| 			 * but before vsync where vpos would turn negative and | ||||
| 			 * the hw counter really increments. | ||||
| 			 */ | ||||
| 			if (vpos >= 0) | ||||
| 				count++; | ||||
| 		} | ||||
| 	} | ||||
| 	else { | ||||
| 	    /* Fallback to use value as is. */ | ||||
| 	    count = radeon_get_vblank_counter(rdev, crtc); | ||||
| 	    DRM_DEBUG_VBL("NULL mode info! Returned count may be wrong.\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	return count; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  | ||||
| @ -367,6 +367,7 @@ struct radeon_crtc { | ||||
| 	u32 line_time; | ||||
| 	u32 wm_low; | ||||
| 	u32 wm_high; | ||||
| 	u32 lb_vblank_lead_lines; | ||||
| 	struct drm_display_mode hw_mode; | ||||
| 	enum radeon_output_csc output_csc; | ||||
| }; | ||||
| @ -553,6 +554,7 @@ struct radeon_connector { | ||||
| 	void *con_priv; | ||||
| 	bool dac_load_detect; | ||||
| 	bool detected_by_load; /* if the connection status was determined by load */ | ||||
| 	bool detected_hpd_without_ddc; /* if an HPD signal was detected on DVI, but ddc probing failed */ | ||||
| 	uint16_t connector_object_id; | ||||
| 	struct radeon_hpd hpd; | ||||
| 	struct radeon_router router; | ||||
| @ -686,6 +688,9 @@ struct atom_voltage_table | ||||
| 	struct atom_voltage_table_entry entries[MAX_VOLTAGE_ENTRIES]; | ||||
| }; | ||||
| 
 | ||||
| /* Driver internal use only flags of radeon_get_crtc_scanoutpos() */ | ||||
| #define USE_REAL_VBLANKSTART 		(1 << 30) | ||||
| #define GET_DISTANCE_TO_VBLANKSTART	(1 << 31) | ||||
| 
 | ||||
| extern void | ||||
| radeon_add_atom_connector(struct drm_device *dev, | ||||
|  | ||||
| @ -1756,7 +1756,9 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev) | ||||
| 	 */ | ||||
| 	for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) { | ||||
| 		if (rdev->pm.active_crtcs & (1 << crtc)) { | ||||
| 			vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, 0, | ||||
| 			vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, | ||||
| 								crtc, | ||||
| 								USE_REAL_VBLANKSTART, | ||||
| 								&vpos, &hpos, NULL, NULL, | ||||
| 								&rdev->mode_info.crtcs[crtc]->base.hwmode); | ||||
| 			if ((vbl_status & DRM_SCANOUTPOS_VALID) && | ||||
|  | ||||
| @ -813,7 +813,7 @@ int rs600_irq_process(struct radeon_device *rdev) | ||||
| 		status = rs600_irq_ack(rdev); | ||||
| 	} | ||||
| 	if (queue_hotplug) | ||||
| 		schedule_work(&rdev->hotplug_work); | ||||
| 		schedule_delayed_work(&rdev->hotplug_work, 0); | ||||
| 	if (queue_hdmi) | ||||
| 		schedule_work(&rdev->audio_work); | ||||
| 	if (rdev->msi_enabled) { | ||||
|  | ||||
| @ -207,6 +207,9 @@ void rs690_line_buffer_adjust(struct radeon_device *rdev, | ||||
| { | ||||
| 	u32 tmp; | ||||
| 
 | ||||
| 	/* Guess line buffer size to be 8192 pixels */ | ||||
| 	u32 lb_size = 8192; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Line Buffer Setup | ||||
| 	 * There is a single line buffer shared by both display controllers. | ||||
| @ -243,6 +246,13 @@ void rs690_line_buffer_adjust(struct radeon_device *rdev, | ||||
| 		tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q; | ||||
| 	} | ||||
| 	WREG32(R_006520_DC_LB_MEMORY_SPLIT, tmp); | ||||
| 
 | ||||
| 	/* Save number of lines the linebuffer leads before the scanout */ | ||||
| 	if (mode1) | ||||
| 		rdev->mode_info.crtcs[0]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode1->crtc_hdisplay); | ||||
| 
 | ||||
| 	if (mode2) | ||||
| 		rdev->mode_info.crtcs[1]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode2->crtc_hdisplay); | ||||
| } | ||||
| 
 | ||||
| struct rs690_watermark { | ||||
|  | ||||
| @ -2376,6 +2376,9 @@ static void dce6_program_watermarks(struct radeon_device *rdev, | ||||
| 		c.full = dfixed_div(c, a); | ||||
| 		priority_b_mark = dfixed_trunc(c); | ||||
| 		priority_b_cnt |= priority_b_mark & PRIORITY_MARK_MASK; | ||||
| 
 | ||||
| 		/* Save number of lines the linebuffer leads before the scanout */ | ||||
| 		radeon_crtc->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay); | ||||
| 	} | ||||
| 
 | ||||
| 	/* select wm A */ | ||||
| @ -6848,7 +6851,7 @@ restart_ih: | ||||
| 	if (queue_dp) | ||||
| 		schedule_work(&rdev->dp_work); | ||||
| 	if (queue_hotplug) | ||||
| 		schedule_work(&rdev->hotplug_work); | ||||
| 		schedule_delayed_work(&rdev->hotplug_work, 0); | ||||
| 	if (queue_thermal && rdev->pm.dpm_enabled) | ||||
| 		schedule_work(&rdev->pm.dpm.thermal.work); | ||||
| 	rdev->ih.rptr = rptr; | ||||
|  | ||||
| @ -67,6 +67,7 @@ static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj, | ||||
| 	 * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap(). | ||||
| 	 */ | ||||
| 	vma->vm_flags &= ~VM_PFNMAP; | ||||
| 	vma->vm_pgoff = 0; | ||||
| 
 | ||||
| 	ret = dma_mmap_attrs(drm->dev, vma, rk_obj->kvaddr, rk_obj->dma_addr, | ||||
| 			     obj->size, &rk_obj->dma_attrs); | ||||
|  | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user